chore(metodo): reparto — C26 contaba el BUCLE y no la condicion (rojos falsos)

Arreglo del linter comun + dos railes. C26 contaba los commits RECIENTES en
vez de los DEFECTUOSOS: en `poniente` decia "24 de las ULTIMAS 48 H" con
CERO commits sin `Sesion:`, y dos lineas mas abajo "todos dicen quien los
hizo". Lo cazo la sesion de poniente. Cuatro controles en repo de laboratorio.

 RAIL: UN GATE QUE ENROJECE POR MOTIVOS FALSOS NO SE IGNORA DE GOLPE, SE
IGNORA POCO A POCO — y ese es el modo en que muere. El aviso esta en el texto
de la excusa: si en dos commits seguidos has tenido que explicar por que el
rojo no cuenta, el defecto esta en el GATE.
⇒ Un check con dos lineas que se contradicen ya te ha dicho cual miente: la
que se calcula APARTE del recuento que tiene casos con nombre. Un agregado
sin la lista de sus miembros no se puede auditar.

Cicatriz C-180. Reparto byte a byte desde la matriz; nada mas que .metodo/.

Sesion: superadmin

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
sirxavor 2026-09-05 08:38:01 +02:00
parent 4a9e34129a
commit 690599413d
4 changed files with 335 additions and 5 deletions

View File

@ -1,5 +1,5 @@
0b309b932d65419946a6e9bfd7e39d164693789a90b4be75a6655c146d3fce84 metodo.md 960cba77494084b39c2291441ed63d090a03bd973701035a89b152597a289f32 metodo.md
71b3e3ace88ef15f0f18b3c0d7a4c5b6a340414a881042d0cc2bd4e8f2583d58 bin/metodo 17f68a7479044cc5b5557d53846839a85c8a1248db7f088431a0392302714dac bin/metodo
f89b71bdf31028b05075636c1763c964e379bc37a00e0357d1c23a4dd19c09aa workflows/README.md f89b71bdf31028b05075636c1763c964e379bc37a00e0357d1c23a4dd19c09aa workflows/README.md
cc241bbecf9647c747b8525b3a6b527455cd50ca0312caa44bc3544342c8ac41 workflows/comunicacion-entre-sesiones.md cc241bbecf9647c747b8525b3a6b527455cd50ca0312caa44bc3544342c8ac41 workflows/comunicacion-entre-sesiones.md
2b9037f6dd57b5598c70a676cb728556654f05d1c5b024e7b716864659f7b884 workflows/sesion-ejecucion.md 2b9037f6dd57b5598c70a676cb728556654f05d1c5b024e7b716864659f7b884 workflows/sesion-ejecucion.md

View File

@ -127,7 +127,7 @@ check_sesion_trailer() {
desde=$(grep -E '^sesion_desde:' "$md/VERSION" 2>/dev/null | sed 's/sesion_desde:[[:space:]]*//') desde=$(grep -E '^sesion_desde:' "$md/VERSION" 2>/dev/null | sed 's/sesion_desde:[[:space:]]*//')
[ -n "$desde" ] || { info "sin punto de adopción todavía — se sella en el próximo 'metodo update'"; return 0; } [ -n "$desde" ] || { info "sin punto de adopción todavía — se sella en el próximo 'metodo update'"; return 0; }
git -C "$ROOT" cat-file -e "$desde^{commit}" 2>/dev/null || { skip "el punto de adopción $desde no existe en este repo"; return 0; } git -C "$ROOT" cat-file -e "$desde^{commit}" 2>/dev/null || { skip "el punto de adopción $desde no existe en este repo"; return 0; }
n=0; mal=0; local exc=0 excf="$ROOT/.metodo/EXCEPCIONES" n=0; mal=0; local rec26=0 _e26; local exc=0 excf="$ROOT/.metodo/EXCEPCIONES"
# ⛔ Un punto de adopción por SHA NO acota en una historia DIVERGENTE: `X..HEAD` incluye # ⛔ Un punto de adopción por SHA NO acota en una historia DIVERGENTE: `X..HEAD` incluye
# todo lo no alcanzable desde X — incluido trabajo ANTERIOR a X hecho en otra rama, que # todo lo no alcanzable desde X — incluido trabajo ANTERIOR a X hecho en otra rama, que
# entra al hacer merge. Medido: un repo con 14 commits ajenos por delante quedó con esos # entra al hacer merge. Medido: un repo con 14 commits ajenos por delante quedó con esos
@ -146,11 +146,21 @@ check_sesion_trailer() {
# Copiar la consulta de C25 tal cual NO casa NUNCA y el gate se queda rojo en silencio. # Copiar la consulta de C25 tal cual NO casa NUNCA y el gate se queda rojo en silencio.
# ⇒ se compara por PREFIJO (>=7) para admitir las dos formas. Medido con control negativo. # ⇒ se compara por PREFIJO (>=7) para admitir las dos formas. Medido con control negativo.
if [ -f "$excf" ] && awk -v s="$sha" '$1=="C26" && length($2)>=7 && index(s,$2)==1 {f=1} END{exit !f}' "$excf"; then exc=$((exc+1)); continue; fi if [ -f "$excf" ] && awk -v s="$sha" '$1=="C26" && length($2)>=7 && index(s,$2)==1 {f=1} END{exit !f}' "$excf"; then exc=$((exc+1)); continue; fi
bad "commit sin 'Sesion:' — $(git -C "$ROOT" log -1 --format='%h %s' "$sha" | cut -c1-60) (C26) — si lo hiciste A MANO, vale 'Sesion: xavier'; si aún no está empujado, un 'git commit --amend' sobre TU commit lo cierra sin excepciones"; mal=$((mal+1)); } bad "commit sin 'Sesion:' — $(git -C "$ROOT" log -1 --format='%h %s' "$sha" | cut -c1-60) (C26) — si lo hiciste A MANO, vale 'Sesion: xavier'; si aún no está empujado, un 'git commit --amend' sobre TU commit lo cierra sin excepciones"; mal=$((mal+1))
# ⛔ Estas dos lineas TIENEN que vivir DENTRO de este bloque. Estuvieron FUERA y el
# contador conto TODOS los commits recientes en vez de los que fallan: en `poniente`
# dijo «24 de las ultimas 48 H» con CERO commits sin `Sesion:`, y dos lineas mas abajo
# el mismo check imprimia «todos dicen quien los hizo». Lo cazo proyectos-95.
# ⇒ C25 tiene el mismo contador y NO tiene el fallo, porque alli el camino bueno hace
# `continue`; aqui es un `|| { }` y se cae dentro por el borde. Misma idea, dos formas.
_e26=$(git -C "$ROOT" log -1 --format=%ct "$sha" 2>/dev/null)
[ -n "$_e26" ] && [ $(( $(date +%s) - _e26 )) -lt 172800 ] && rec26=$((rec26+1))
}
done <<EOF done <<EOF
$(git -C "$ROOT" rev-list --no-merges "$desde..HEAD" 2>/dev/null) $(git -C "$ROOT" rev-list --no-merges "$desde..HEAD" 2>/dev/null)
EOF EOF
[ "$exc" -gt 0 ] && warn "C26: ${exc} commit(s) con EXCEPCIÓN DECLARADA en .metodo/EXCEPCIONES (historia ya empujada; NO perdona lo que venga después)" [ "$exc" -gt 0 ] && warn "C26: ${exc} commit(s) con EXCEPCIÓN DECLARADA en .metodo/EXCEPCIONES (historia ya empujada; NO perdona lo que venga después)"
[ "$rec26" -gt 0 ] && bad "C26: ${rec26} de los ${mal} commit(s) SIN 'Sesion:' son de las ULTIMAS 48 H — no es deuda historica, esta creciendo HOY"
[ "$mal" -eq 0 ] && ok "$n commit(s) desde la adopción, todos dicen quién los hizo" [ "$mal" -eq 0 ] && ok "$n commit(s) desde la adopción, todos dicen quién los hizo"
} }
@ -595,6 +605,7 @@ check_commits() {
# Formato de `.metodo/EXCEPCIONES` (del repo; NO se vendoriza — cada uno lleva las suyas): # Formato de `.metodo/EXCEPCIONES` (del repo; NO se vendoriza — cada uno lleva las suyas):
# C25 <sha> <AAAA-MM-DD> <motivo en una línea> # C25 <sha> <AAAA-MM-DD> <motivo en una línea>
local excf="$ROOT/.metodo/EXCEPCIONES" exc_c=0 sha subj local excf="$ROOT/.metodo/EXCEPCIONES" exc_c=0 sha subj
local rec_c=0 _e
while IFS=$'\t' read -r sha subj; do while IFS=$'\t' read -r sha subj; do
[ -n "$sha" ] || continue [ -n "$sha" ] || continue
printf '%s' "$subj" | grep -qE '^(feat|fix|docs|ci|refactor|test|chore|build|perf|deploy|doc|semaforo|semáforo|avisos|semaforo|semáforo|avisos|bitacora|bitácora|decisiones|backlog|corpus|evidencia|banco|fix|docs|ci|refactor|test|chore|build|perf|semaforo|semáforo)(\(.+\))?!?: .' && continue printf '%s' "$subj" | grep -qE '^(feat|fix|docs|ci|refactor|test|chore|build|perf|deploy|doc|semaforo|semáforo|avisos|semaforo|semáforo|avisos|bitacora|bitácora|decisiones|backlog|corpus|evidencia|banco|fix|docs|ci|refactor|test|chore|build|perf|semaforo|semáforo)(\(.+\))?!?: .' && continue
@ -603,8 +614,11 @@ check_commits() {
fi fi
bad "commit no-Conventional: \"$subj\" ($sha) (C25) — arréglalo, o decláralo en .metodo/EXCEPCIONES si ya está empujado" bad "commit no-Conventional: \"$subj\" ($sha) (C25) — arréglalo, o decláralo en .metodo/EXCEPCIONES si ya está empujado"
bad_c=$((bad_c+1)) bad_c=$((bad_c+1))
_e=$(git -C "$ROOT" log -1 --format=%ct "$sha" 2>/dev/null)
[ -n "$_e" ] && [ $(( $(date +%s) - _e )) -lt 172800 ] && rec_c=$((rec_c+1))
done < <(git -C "$ROOT" log --no-merges --format="%h%x09%s" $range 2>/dev/null) done < <(git -C "$ROOT" log --no-merges --format="%h%x09%s" $range 2>/dev/null)
[ "$exc_c" -gt 0 ] && warn "C25: ${exc_c} commit(s) con EXCEPCIÓN DECLARADA en .metodo/EXCEPCIONES (historia ya empujada; NO perdona lo que venga después)" [ "$exc_c" -gt 0 ] && warn "C25: ${exc_c} commit(s) con EXCEPCIÓN DECLARADA en .metodo/EXCEPCIONES (historia ya empujada; NO perdona lo que venga después)"
[ "$rec_c" -gt 0 ] && bad "C25: de esos, ${rec_c} son de las ULTIMAS 48 H — esto no es deuda historica, esta creciendo HOY"
[ "$bad_c" -eq 0 ] && ok "los ${n} commit(s) desde la adopción siguen Conventional$([ "$exc_c" -gt 0 ] && printf ' (%s con excepción declarada)' "$exc_c")" [ "$bad_c" -eq 0 ] && ok "los ${n} commit(s) desde la adopción siguen Conventional$([ "$exc_c" -gt 0 ] && printf ' (%s con excepción declarada)' "$exc_c")"
} }

View File

@ -1353,3 +1353,152 @@ La superadmin, 2026-09-03: **el gate del reparto estuvo ROJO durante horas en lo
señaló `poniente`, que **lo decía en cada commit en vez de silenciarlo** — que es lo que impide señaló `poniente`, que **lo decía en cada commit en vez de silenciarlo** — que es lo que impide
acostumbrarse. acostumbrarse.
### C-169
`securizacion`, 2026-09-03: la ejecución acusó a su orquestadora de haberse llevado su fila del
semáforo. **Se midió antes de aceptar o negar**, y no era ella:
```
94f610e (el suyo) -> 1 fichero, 1 linea: la fila de la ORQUESTADORA
8885f2c "sello del reparto" -> ULTIMO-REPARTO + la fila de la EJECUCION
```
⇒ ⭐ **Por qué se lo pareció**: el mensaje decía *«semaforo: securizacion en pausa»* **y su diff
contenía la palabra `PAUSADA`** — porque la había escrito **en su propia fila**. **Dos hechos ciertos
compuestos en una conclusión falsa**: ninguno mentía y **ninguno contestaba a la pregunta**.
**Por eso no lo caza mirar con más cuidado: sólo lo caza CAMBIAR LA PREGUNTA** — de *«¿este commit
encaja con lo que me pasó?»* a *«¿este commit contiene MI cambio?»*. La retiró ella con `git log -S`.
### C-170
2026-09-03, 20:15, medido por **dos sesiones distintas por separado**: en `ListAgents` **las seis
sesiones vivas aparecen como «started 16 m ago»** — incluida una con **21 commits ese día** y el
último seis horas antes, e incluida la propia superadmin, que llevaba la jornada entera. ⇒ **La edad
del listado es cuándo el listado la vio, no la edad de la sesión.**
**Y lo peor, que encontró `poniente`: el `[ref]` TAMPOCO es estable.** La misma sesión, **sin
reiniciar, mismo hilo, mismo día y sin ningún corte**, se vio a sí misma con **dos refs distintos**:
`[47a547]` por la mañana y `[0eb362]` por la tarde. **Y el `[ref]` es justo lo que la herramienta
ofrece para desambiguar dos sesiones con el mismo nombre.**
⚠️ La superadmin llegó a concluir que esa sesión **era otra distinta** y estuvo a punto de dejar sus
**cuatro `D` del día huérfanas** en la tabla — con otro frente pudiendo tomarlo por libre. Lo refutó
la propia sesión **con sus commits y sus horas**, no con una afirmación.
### C-171
2026-09-03: la superadmin declaró *«`coredns-admin` está caído»* midiendo `192.168.0.110` **desde
este PC** —ping sin respuesta, tcp/53 sin abrir—. **Dos errores sumados y ninguno era el servicio:**
**(a)** esa IP **no se alcanza desde fuera de la red del trabajo**, y desde `srvfkvm01` resolvía
perfectamente; **(b)** y aunque se alcanzara, **el test era categóricamente el equivocado**. Xavier
dio el mecanismo: **las IP de MetalLB no contestan a ping — se anuncian por ARP.** Una IP de
`LoadBalancer` en L2 **no es la interfaz de nadie**: la publica un *speaker* y **sólo existe para los
puertos que declara el `Service`** —aquí `53/UDP` y `53/TCP`—, así que **ICMP no tiene dónde
aterrizar**. ⇒ El mismo día, otra sesión midió `100 % de pérdida` contra esa IP **y resolución
perfecta**.
### C-172
`securizacion` (ejecución), madrugada del 2026-09-04. **⑴** Un mutante cuyo `sed` **no casaba**
producía un fichero **idéntico**. La aserción salía **verde, y con razón** —no había nada que ver— y
**el arnés lo anotaba como *«la aserción no ve su propio mutante»***. ⇒ **Acusaba a la mitad
equivocada** y mandaba a depurar una aserción sana. El arreglo: **una puerta previa que compara el
fichero antes de juzgar**; si no cambió, **el defecto es del mutante**, y se dice con esas palabras.
**⑵** Y esa puerta destapó, **en la misma pasada**, que otra aserción llevaba **dando verde falso**:
su `sed` usaba `#` de delimitador sobre un patrón que contiene `####`, así que **nunca aplicó** — y
salía verde **porque el arnés llevaba una copia vieja del criterio**, corregido esa misma noche.
⇒ ⭐⭐ **⑴ era la ÚNICA forma de encontrar ⑵**: sin la puerta que distingue *«mutante que no ocurre»*
de *«aserción ciega»*, ese verde falso **habría durado para siempre**, sobre un mutante que **nunca
se aplicó**.
### C-173
`hermes-infra` (ejecución), 2026-09-04: el hierro `jon` se renombró a **`aegon`**, y su banco lleva un
**censo sobre hosts reales** — un censo sin sujeto **aprueba sobre la nada**. Comprobado y **no se
rompió**: `b4-45-06-e9-38-67 → rhaegar.yaml` y `b4-45-06-e9-4a-79 → aegon.yaml`, los dos con dueño.
⇒ ⭐ **Y sobrevivió por diseño, no por suerte: el censo direcciona por MAC —IDENTIDAD— y no por
nombre de host, que es una ETIQUETA.** Escrito con `jon`, **habría quedado mudo con el rename sin dar
error**.
⚠️ En la misma medida, su primer `grep` salió **vacío** por buscar con comillas simples una cadena
entre dobles; lo repitió **con control positivo** (13 rutas). *Un filtro que no casa no se queja.*
### C-174
La superadmin, 2026-09-04: `hermes-infra` pidió una sesión de ejecución y **se le ofreció el encargo
a una que venía de otro frente, en frío del motor** — mientras **su propio satélite, con el contexto
del motor y el banco en la cabeza, estaba ocioso esperando encargo**. La superadmin **no lo había
identificado todavía**: lo listaba como *«sin fichar»* y le mandó la ronda **después** de haber
repartido el encargo. ⇒ **El orden estaba invertido: se asignó trabajo antes de saber quién había.**
### C-175
`hermes-infra`, 2026-09-04, corrigiendo el barrido de la superadmin tras una posible suspensión del
PC: se preguntó a las siete sesiones *«¿queda algo sin empujar que no estuviera antes?»* — y la
respuesta fue: **«yo no tengo un ANTES fiable contra el que comparar»**. ⇒ **Todas contestaron
«limpio» con la misma confianza, tuvieran razón o no.** El instrumento medía **la memoria de cada
sesión**, no el árbol. ⇒ Lo que hacía falta era **un `sha` por repo anotado ANTES**, y no existía.
### C-176
`securizacion`, 2026-09-04/05, **y la sesión que lo trajo se refutó a sí misma el mecanismo entero**.
Primero lo contó como *«una excepción declarada quita la señal y deja crecer el defecto sin
testigo»*. **Falso aquí, y lo desmiente el propio fichero que citaba**: su cabecera dice *«aquí dejan
de gatear, pero **siguen contándose e imprimiéndose en cada corrida**»*, y el `check` lo confirma
—`nota C25: 14 con EXCEPCIÓN DECLARADA`—. **El mecanismo está diseñado para no hacer lo que se le
atribuyó.** Y el «49» tampoco era el fichero: era **10 declarados + 39 commits nuevos**, *«una suma de
dos sujetos distintos vendida como censo»*.
⇒ ⭐ **Lo que pasó de verdad, medido y reproducido por la superadmin**: **45 commits en rojo, 18 del
3-sep y 27 del 4 — ninguno anterior**, sin declarar y **en rojo todo el tiempo**. *«La señal estuvo
ahí cuatro días y nadie la miró. Yo incluida: corrí `metodo check`, vi «89 avisos» y **lo leí como
deuda histórica**.»*
⇒ **No es «la excepción lo escondió»: es «el rojo era visible y se leyó como pasado».**
### C-177
`hermes-infra`, 2026-09-04, **retirando un aviso propio por falso**: se midió
`NextElapseUSecMonotonic=infinity` en un temporizador y se dedujo *«este nodo ha dejado de converger
para siempre, pintándose verde»*. Se escribió como aviso **y se mandó a otra casa con recomendación
de actuar**. ⛔ **Era falso**: ese valor **no dice que el temporizador esté muerto — dice que el
servicio que dispara está corriendo AHORA**.
✅ Lo que sobrevivió, en `A40`: **el testigo de que un nodo converge no es ninguna propiedad de la
unidad — es que el TRABAJO ESTÉ HECHO**: `/var/log/infraserver/apply.log` creciendo, con su
`PLAY RECAP` y `failed=0`. **`is-active` da `active` igual en un timer sano que en uno inútil**, y
`Persistent=` es decoración en una unidad monotónica.
### C-178
`hermes-infra`, 2026-09-05: *«el motor ya está gateado»* es **cierto y cubre mucho menos de lo que
suena**. El catálogo declara `gate_target: test` con gate `pytest`, y el pod corre el digest gateado
—medido **en el artefacto**, con `kubectl`, no en el commit—. ⛔ **Pero esa gate corre los 5 tests
unitarios de `tests/`, NO el banco de render**: `src/engine/Dockerfile` tiene **0 menciones de
`banco`**, su stage `test` hace `COPY tests/` y nada más, y `gate.sh` es `pytest tests -q`. **El banco
declara `SUELO = 86` comprobaciones y sigue fuera de la imagen y sin lanzador.** ⇒ **Lo que protege el
arranque PXE no está gateado, y ahora PARECE que sí.** *(La superadmin lo había retransmitido como
«el motor desplegado con digest gateado», sin acotar.)*
### C-179
El semáforo, 2026-09-05: la superadmin midió que la fila 244 llevaba **`🟢`** y la sucesora leyó que
estaba **cerrada**. **Las dos medidas eran correctas**: en la **misma celda** convivían
`🟢 EN VUELO (2026-09-04)` arriba y *«⚰️ CIERRE 2026-09-05, con relevo»* más abajo. **El fichero se
contradecía a sí mismo**, y **ganó el marcador** — porque es lo que se escanea. ⇒ **El fallo no fue de
nadie**: quien escribió el cierre lo escribió bien, **sólo que en el sitio que no gobierna**.
### C-180
`metodo check`, C26, 2026-09-05 — lo cazó la sesión de `poniente`, no la que escribió el código. El
check imprimía **tres líneas seguidas que se contradecían**: `nota: 3 commit(s) con EXCEPCIÓN
DECLARADA` · `AVISO: de esos, 24 son de las ULTIMAS 48 H` · `ok: 81 commit(s), todos dicen quién los
hizo`. ⛔ **«De esos» eran 3, decía 24, y la tercera línea decía que no fallaba ninguno.** Medido: los
commits sin `Sesion:` en 48 h eran **CERO**, y **24 era el total de commits recientes del repo**. La
causa: el contador de «últimas 48 h» estaba **DOS LÍNEAS FUERA** del bloque `|| { … }` que trata el
commit defectuoso, así que se ejecutaba **una vez por commit**, no una vez por fallo. ⭐ **C25 tiene el
mismo contador y NO tiene el fallo**, porque allí el camino bueno hace `continue` y aquí es un
`|| { }` del que se cae dentro por el borde: **la misma idea escrita de dos formas, y sólo una de
ellas perdona el descuido**. ⇒ Y el daño no era la cifra: esa sesión llevaba **dos días** anotando en
cada commit *«GATE: rojo por la matriz, no es de este repo»*. **Un gate que enrojece por motivos
falsos no se ignora de golpe: se ignora poco a poco, y ése es el modo en que muere.** ⚠️ El arreglo se
escribió primero **con un `perl -i -pe` de comillas dobles y el shell se comió los `${rec26}`**,
dejando el mensaje como *«C26: de los commit(s) SIN…»***y `bash -n` dio verde**, porque la sintaxis
era correcta y sólo el texto estaba vacío. ⇒ Reescrito con heredoc en comillas simples. **Cuatro
controles**: el defecto reproducido en laboratorio con el binario viejo (dijo «5 de las últimas 48 H»
con 5 commits buenos), el arreglado callando en el mismo repo, un commit de hoy **realmente** sin
`Sesion:` **enrojeciendo** (`1 de los 2`), y ese mismo commit **arreglado**, que apaga la línea de 48 h
**sin** apagar el rojo del defecto viejo.

View File

@ -139,6 +139,31 @@ cuando **algo EXTERNO a ella tiene que estar de acuerdo**; y *externo* no signif
vez con más cuidado»*: significa **que llegue por una RUTA DISTINTA de la que la produjo**. No vez con más cuidado»*: significa **que llegue por una RUTA DISTINTA de la que la produjo**. No
volver a leerla — **volver a derivarla por otro camino**. volver a leerla — **volver a derivarla por otro camino**.
⛔ **PREGUNTAR «¿HA CAMBIADO ALGO?» SIN UN «ANTES» ESCRITO NO MIDE NADA — mide la memoria del que
contesta.** Y todos contestan **«limpio» con la misma confianza**, tengan razón o no, así que la
respuesta **no distingue el caso bueno del malo**: es un testigo que **no puede decir que no**.
*(cicatriz `C-175`, y lo señaló la sesión a la que se le preguntaba.)*
**El «antes» se ESCRIBE, no se recuerda**: una foto con `sha` por repo, con hora, guardada donde
sobreviva al corte. Sin ella, un barrido tras una caída **produce siete confirmaciones y cero
información**.
⇒ ⭐ Y la forma general, que es la de todo este método: **una comparación necesita DOS medidas, y la
segunda no puede ser un recuerdo.** Cuando pidas un careo, pregunta primero **dónde está la primera
mitad** — si la respuesta es *«en la cabeza de alguien»*, **no hay careo: hay una opinión con formato
de medida**.
⛔ **DIRECCIONA POR IDENTIDAD, NO POR ETIQUETA — o tu comprobación se queda MUDA el día que algo se
renombre, y sin dar error.** Un nombre de host, un tag de imagen, una rama: **son etiquetas y se
mueven**. Una MAC, un digest, un sha: **identifican**. *(cicatriz `C-173`: un banco con censo sobre
hosts reales sobrevivió al rename `jon`→`aegon` **porque direccionaba por MAC**; escrito con el
nombre, **habría aprobado sobre la nada**.)*
⇒ ⭐ **Y el modo de fallo es el peor de los catalogados: un censo que se queda sin sujeto NO falla —
aprueba.** No encuentra nada que juzgar, y *«nada que objetar»* **se escribe igual que un verde**.
⇒ **Antes de escribir una comprobación que enumera, pregunta: ¿por qué campo direcciona, y ese campo
lo puede cambiar alguien sin tocar mi comprobación?** Si la respuesta es sí, **el gate ya está roto y
todavía no lo sabes**.
⛔ **UN FILTRO TEMPORAL MAL ZONIFICADO NO DA ERROR: DA CERO — y el cero se lee como AUSENCIA DEL ⛔ **UN FILTRO TEMPORAL MAL ZONIFICADO NO DA ERROR: DA CERO — y el cero se lee como AUSENCIA DEL
HECHO.** No es que la herramienta calle: **contesta que no hubo nada**, que es la respuesta más HECHO.** No es que la herramienta calle: **contesta que no hubo nada**, que es la respuesta más
peligrosa de todas porque cierra la investigación. *(cicatriz `C-162`)* peligrosa de todas porque cierra la investigación. *(cicatriz `C-162`)*
@ -157,11 +182,41 @@ BUSCABAS.** *(cicatriz `C-163`: `systemctl is-active ufw` dice **`active`** y `u
respuesta, te da **la que esperabas**. Un testigo que niega se investiga; **uno que confirma cierra respuesta, te da **la que esperabas**. Un testigo que niega se investiga; **uno que confirma cierra
la investigación**. ⇒ **Cuando una medida confirme tu hipótesis a la primera, pregúntale a otro la investigación**. ⇒ **Cuando una medida confirme tu hipótesis a la primera, pregúntale a otro
instrumento la MISMA pregunta** — y si los dos vienen del mismo subsistema, **no son dos**. instrumento la MISMA pregunta** — y si los dos vienen del mismo subsistema, **no son dos**.
⛔ **UNA DIRECCIÓN VIRTUAL NO TIENE PILA PROPIA: SÓLO EXISTE PARA LOS PUERTOS QUE DECLARA SU
SERVICIO.** Una IP de `LoadBalancer` en L2 —MetalLB—, una VIP de keepalived o una anycast **no son la
interfaz de ninguna máquina**: alguien las **anuncia por ARP** y el tráfico sólo llega **a los puertos
declarados**. ⇒ **Hacerle `ping` no es una prueba débil: es una prueba de otra cosa**, y su silencio
es **el comportamiento correcto**. *(cicatriz `C-171`)*
**El test de una dirección virtual es SU PUERTO** —`dig @ip`, `curl`, un `/dev/tcp` al puerto que
el `Service` declara—, nunca ICMP. Y si el puerto tampoco responde, **antes de acusar al servicio
comprueba que TÚ alcanzas esa red**: las dos veces que se declaró muerto ese DNS, **el que no llegaba
era el que medía**.
⇒ ⭐ Y la forma general, que es la que se repite: **el silencio de una capa que no participa se lee
como el silencio de la que sí.** ICMP no participa en un `Service` de Kubernetes — igual que un
`CSINode` habla del registro local del kubelet, o un iDRAC contesta por el anfitrión de una VM.
**Antes de leer un silencio, pregunta si esa capa tenía algo que decir.**
⇒ **Esto explica por qué «ten cuidado» no funciona, y por qué todo lo que este Método pide ES ⇒ **Esto explica por qué «ten cuidado» no funciona, y por qué todo lo que este Método pide ES
EXTERNO**: el mutante, el control negativo, la predicción escrita **antes**, el careo contra el EXTERNO**: el mutante, el control negativo, la predicción escrita **antes**, el careo contra el
artefacto, pedir el crudo. **No son disciplina: son un referente que no eres tú.** artefacto, pedir el crudo. **No son disciplina: son un referente que no eres tú.**
⛔⛔ **Y APLICADO A GIT, QUE ES DONDE MÁS SE PARECE A UNA PRUEBA SIN SERLO: UN MENSAJE DE COMMIT ES
LO QUE ALGUIEN CREYÓ QUE ESTABA HACIENDO; EL `-S` ES LO QUE HIZO.** En un árbol que tocan seis
sesiones, **el mensaje es la fuente menos fiable que hay — y la primera que apetece leer.**
*(cicatriz `C-169`)*
**El gesto**: para saber qué commit se llevó tu línea, **`git log -S'<tu texto>' -- <fichero>`**,
y `git show --stat` para el alcance. **Nunca el `%s`.**
⇒ ⛔ **Y el modo de fallo es de los que no se corrigen mirando mejor**: allí **el mensaje y el diff
eran los dos CIERTOS** —hablaban de una pausa, y la palabra estaba en el diff— **y ninguno contestaba
a la pregunta**. **Dos hechos ciertos compuestos en una conclusión falsa** sólo se deshacen
**cambiando la pregunta**: de *«¿encaja con lo que me pasó?»* a *«¿contiene MI cambio?»*.
⇒ ⭐ **Y son TRES testigos que NO se sustituyen**, uno por pregunta: **el contador posicional** dice
que *la pasada es nueva* · **el sha** dice que *corrió TU código* · **`git log -S`** dice que *el
commit es el tuyo*. Tener uno no exime de los otros dos.
ⓘ Y el cuarto sujeto de la misma familia, que conviene ver venir: **la fila del semáforo dice lo
que una sesión DECLARÓ que iba a tocar, no lo que tocó.**
*(cicatriz `C-006`)* *(cicatriz `C-006`)*
@ -737,6 +792,22 @@ una mutación que impide arrancar no mide el sistema, mide el arnés.
⇒ Y **no mutes a un valor que tu test ya espera.** *(cicatriz `C-059`)* Muta a algo ⇒ Y **no mutes a un valor que tu test ya espera.** *(cicatriz `C-059`)* Muta a algo
que **no pueda ocurrir**, no a lo que el sistema usa de verdad. que **no pueda ocurrir**, no a lo que el sistema usa de verdad.
⛔⛔ **Y UN QUINTO MODO, QUE NO ES DE LA ASERCIÓN SINO DEL ARNÉS — Y SU FALLO NO ES CALLARSE: ES
ACUSAR AL INOCENTE.** Los cuatro de arriba son defectos **de la aserción**; éste es del **instrumento
que la juzga**, y por eso no se parece a ninguno: **no da un verde falso ni un rojo falso — da un
diagnóstico falso**, y te manda a arreglar la mitad sana. *(cicatriz `C-172`)*
⇒ **La pregunta que hay que hacerle a cualquier arnés de mutación, y es una línea de código:**
***«cuando un mutante no cambia nada, ¿lo sabes, o lo cuentas como que la aserción falló?»*** —
**cambia a quién acusa el instrumento**. ⇒ La guarda de `§3` *(afirmar que el fichero cambió)* ya
existía; lo que faltaba es **usarla para ATRIBUIR**, no sólo para abortar: *«el mutante no ocurrió»* y
*«la aserción está ciega»* **son dos veredictos distintos y el arnés los daba como uno**.
⇒ ⭐⭐ **Y la capa, que es lo que hay que llevarse: EL PUNTO CIEGO DE UN CONTROL SÓLO LO ENCUENTRA UN
CONTROL UNA CAPA POR ENCIMA. Si esa capa no existe, la ceguera es PERMANENTE — y tiene aspecto de
salud.** En el caso medido, la puerta nueva destapó **en su primera pasada** un verde falso que
llevaba vivo sobre un mutante **que nunca se había aplicado**: sin ella **no había forma de verlo**,
porque el síntoma era **la ausencia de síntoma**.
**Y el propio ARNÉS es código sin tests — y falla hacia el VERDE.** Todo lo de arriba supone que **Y el propio ARNÉS es código sin tests — y falla hacia el VERDE.** Todo lo de arriba supone que
la comprobación dice lo que crees; cuando no, el error es asimétrico, porque en un arnés el camino la comprobación dice lo que crees; cuando no, el error es asimétrico, porque en un arnés el camino
que no se ejecuta suele ser el que declara `ok`. *(cicatriz `C-060`)* que no se ejecuta suele ser el que declara `ok`. *(cicatriz `C-060`)*
@ -1395,6 +1466,21 @@ ti. Tres amortiguadores, tres cicatrices, un solo mecanismo:
- **UPTIME: el proceso vivo.** Sostiene en memoria cosas que ya no existen fuera, y **el reinicio no - **UPTIME: el proceso vivo.** Sostiene en memoria cosas que ya no existen fuera, y **el reinicio no
rompe nada: es cuando se descubre lo que llevaba roto**. *(cicatriz `C-108`)* ⇒ **Un `uptime` largo es motivo de SOSPECHA, no de confianza.** rompe nada: es cuando se descubre lo que llevaba roto**. *(cicatriz `C-108`)* ⇒ **Un `uptime` largo es motivo de SOSPECHA, no de confianza.**
⛔ **EL TESTIGO DE QUE ALGO SIGUE FUNCIONANDO NO ES UNA PROPIEDAD DEL MECANISMO: ES QUE EL TRABAJO
ESTÉ HECHO.** Un temporizador `active`, un proceso vivo, una conexión establecida, un `Deployment`
`Available`**todos dicen que el mecanismo existe, ninguno dice que haya producido nada**.
*(cicatriz `C-177`)*
⇒ ⛔ **Y una comprobación de salud de parque que sólo mire el mecanismo da VERDE sobre nodos que
llevan semanas sin aplicar nada.** El testigo bueno es **el rastro del trabajo**: un log que crece,
un recap con `failed=0`, un artefacto con fecha de hoy.
⇒ ⚠️ **Y el aviso que va con esto, porque es cómo se falla al intentarlo**: leer una propiedad interna
del mecanismo **e inferir su salud** produce avisos falsos **que suenan muy técnicos**. En el caso
medido, `NextElapseUSecMonotonic=infinity` **no significa «muerto»: significa «disparando ahora»**
y de ahí salió un aviso que **se mandó a otra casa con recomendación de actuar** antes de retirarse.
⇒ ⭐ **Antes de deducir salud de un campo interno, pregunta qué significa ese campo cuando el sistema
está SANO.** Si no lo sabes, **no es un testigo: es una lectura.**
⇒ ⭐ **El remedio es el mismo en los tres: QUITA EL AMORTIGUADOR Y VUELVE A MEDIR.** Apaga el camino ⇒ ⭐ **El remedio es el mismo en los tres: QUITA EL AMORTIGUADOR Y VUELVE A MEDIR.** Apaga el camino
alterno · mide en el aparato más apretado, no en el más holgado · **reinicia, o carea lo que el alterno · mide en el aparato más apretado, no en el más holgado · **reinicia, o carea lo que el
proceso cree contra lo que hay HOY en su origen** (el registro, el fichero, el secreto). proceso cree contra lo que hay HOY en su origen** (el registro, el fichero, el secreto).
@ -1465,6 +1551,61 @@ sobreviva a eso** se arregla o se declara como excepción **nominal, fechada y m
⛔ Y el corolario que lo hace operativo: **acostumbrarse a un rojo es el mecanismo**, así que quien ⛔ Y el corolario que lo hace operativo: **acostumbrarse a un rojo es el mecanismo**, así que quien
llega nuevo a un frente **es el único que puede verlo** — si arrancas en un sitio y su gate sale llega nuevo a un frente **es el único que puede verlo** — si arrancas en un sitio y su gate sale
rojo, **dilo ese día**; después ya te habrás acostumbrado tú. rojo, **dilo ese día**; después ya te habrás acostumbrado tú.
⛔⛔ **UN ROJO GRANDE Y APARENTEMENTE ANTIGUO ESCONDE QUE ESTÁ CRECIENDO HOY.** Un contador grande
**se lee como historia**: nadie audita 89 avisos, se asume que vienen de lejos y **se dejan para
cuando haya tiempo**. ⇒ **El número no distingue «deuda de hace meses» de «costumbre de anteayer»**,
y las dos cosas piden reacciones opuestas. *(cicatriz `C-176`)*
⇒ ⭐ **El instrumento que lo caza es barato y no depende de que nadie lea un cartel: QUE EL GATE
REPARTA EL ROJO POR EDAD.** *«89 avisos»* se archiva; **«45 avisos, TODOS de las últimas 48 h»** no
se puede leer como pasado. *(Atado el 2026-09-05 en `C25` y `C26`: cuentan aparte los commits de
menos de 48 h y lo dicen con esas palabras. Medido al estrenarlo: `securizacion` **41 y 109**,
`poniente` **27** — y el «control negativo» **dejó de ser negativo porque la condición se cumplía
de verdad**, que es la mejor forma de estrenar un gate.)*
⇒ ⛔ **Y la mitad que corrige el instinto**: ante un rojo crónico, la pregunta **no** es *«¿cuánto
llevamos así?»* sino **«¿cuánto de esto es de esta semana?»**. Si la respuesta es *«todo»*, **no hay
deuda: hay un hábito**, y arreglar el pasado no arregla nada.
⛔⛔ **UN GATE QUE ENROJECE POR MOTIVOS FALSOS NO SE IGNORA DE GOLPE: SE IGNORA POCO A POCO — Y ÉSE ES
EL MODO EN QUE MUERE.** No hace falta que nadie decida desatenderlo. Basta con que el rojo **sea
verdadero pero no sea tuyo** —la matriz cambió, otro repo va por delante— o que **sea sencillamente
falso**: a la segunda vez, la sesión escribe en su commit *«GATE: rojo, no es de este repo»* y sigue.
**A partir de ahí el gate ya no informa: se justifica.** *(cicatriz `C-180`: dos días de esa nota
seguidos, con un rojo legítimo-ajeno y otro producto de un bug.)*
⇒ ⭐ **El aviso está en el propio texto de la excusa**: si en dos commits seguidos has tenido que
**explicar por qué el rojo no cuenta**, el defecto ya no está en el trabajo — **está en el gate**, y
arreglarlo es la tarea, no un rodeo.
⇒ ⛔ **Y un check que imprime dos líneas que se contradicen ya te ha dicho cuál miente**: la que
**se calcula aparte** del recuento que sí tiene un caso concreto detrás. C26 decía *«24 de las últimas
48 h»* y, **dos líneas más abajo**, *«todos dicen quién los hizo»*; las cifras con nombre y apellido
eran ciertas y **la agregada no**. **Un agregado sin la lista de sus miembros no se puede auditar**
**el contador que enrojece imprime también QUIÉNES**, o no es un testigo, es una afirmación.
⇒ ⭐ **Y la causa, que se repite**: el contador estaba **dos líneas FUERA** del bloque que trata el
caso defectuoso, así que **contaba el bucle, no la condición**. El check hermano tenía el mismo
contador **sin el fallo**, porque su camino bueno hace `continue` y aquí era un `|| { … }` **del que se
cae dentro por el borde**. ⇒ **La misma idea escrita de dos formas, y sólo una perdona el descuido**:
cuando dupliques una comprobación, **copia la FORMA, no sólo la intención**.
⛔⛔ **UNA GATE ESTRECHA CON NOMBRE ANCHO ES PEOR QUE NO TENER GATE: RETIRA LA SOSPECHA SIN RETIRAR EL
RIESGO.** *«Está gateado»* se propaga como cobertura total, y a partir de ahí **nadie vuelve a
preguntar qué cubre**. Sin gate, el hueco al menos **se llama `ungated` y se ve**.
*(cicatriz `C-178`: la gate del motor corre **5 tests unitarios**; el banco que protege el arranque
PXE, con **86 comprobaciones declaradas**, **no entra en la imagen y no lo lanza nadie** — y el
`Dockerfile` no lo menciona **ni una vez**.)*
**Al declarar una gate, escribe QUÉ NO CUBRE en el mismo sitio donde se declara** — no en su
bitácora. Y al oír *«ya está gateado»*, la pregunta es **«¿qué ficheros ejecuta esa gate?»**, no
*«¿está verde?»*.
⇒ ⭐ Y el testigo, que aquí se hizo bien: **se midió en el ARTEFACTO** —el digest que corre el pod,
con `kubectl`**no en el commit que dice haberlo puesto**.
⛔ **UN ESTADO DECLARADO EN DOS SITIOS ACABA DISCREPANDO — Y GANA EL QUE SE LEE DE UN VISTAZO.**
*(cicatriz `C-179`: una fila del semáforo llevaba **`🟢` arriba y «CIERRE» en el texto de la misma
celda**; dos sesiones la midieron distinto **y las dos tenían razón**. Ganó el marcador, porque es lo
que se escanea.)*
⇒ ⭐ **Y no culpes a quien escribió el segundo sitio: escribió bien, sólo que donde no gobierna.**
**Antes de escribir un estado, pregunta cuál es el campo que la herramienta LEE** —el marcador, la
columna, el `status`— y **escríbelo ahí**. Lo demás es prosa de apoyo, y **la prosa no gobierna**.
⇒ ⭐ **Lo único que convierte un aviso en un gate es un NÚMERO QUE TIENE QUE CUADRAR**, y que ese ⇒ ⭐ **Lo único que convierte un aviso en un gate es un NÚMERO QUE TIENE QUE CUADRAR**, y que ese
número mueva el **código de salida**, no la pantalla. Las tres formas que ya existen en el árbol, y número mueva el **código de salida**, no la pantalla. Las tres formas que ya existen en el árbol, y
@ -1521,6 +1662,18 @@ lo recibe tiene que saber si abre sesión nueva o lo pega en la que ya corre. *(
propias premisas, y el raíl 6 dice que de lo heredado hay que re-verificar **más**, no menos. Si la propias premisas, y el raíl 6 dice que de lo heredado hay que re-verificar **más**, no menos. Si la
tarea es comprobar, medir o poner en duda → **fría, siempre**. Construir encima → caliente. tarea es comprobar, medir o poner en duda → **fría, siempre**. Construir encima → caliente.
⛔ **ASIGNAR TRABAJO ANTES DE SABER QUIÉN HAY ES REPARTIR A CIEGAS — y el coste no es el retraso: es
que la que tiene el contexto se queda parada mientras una de fuera arranca en frío.**
*(cicatriz `C-174`: la superadmin ofreció un encargo del motor a una sesión de otro frente **teniendo
al satélite del propio motor ocioso y esperando encargo**; le mandó la ronda de identificación
**después** de repartir.)*
⇒ **En el protocolo de arranque, la ronda ⓪ va ANTES de cualquier reparto, y «sin fichar» no es un
detalle pendiente: es un HUECO EN EL CENSO.** Una sesión sin identificar **no es una sesión que no
existe: es una que no sabes qué sabe.**
⇒ ⭐ Y el corolario para quien coordina: **el criterio de asignación no es «quién está libre», es
«quién ya tiene el contexto»** — y eso sólo se sabe **después** de preguntar.
⛔ **LO PRIMERO DE UNA ORQUESTADORA ES UN `git pull` — Y SI TRAE ALGO NUEVO, MEDIRLO ANTES DE ⛔ **LO PRIMERO DE UNA ORQUESTADORA ES UN `git pull` — Y SI TRAE ALGO NUEVO, MEDIRLO ANTES DE
SEGUIR** *(Xavier, 2026-08-29)*. No es higiene de git: es que **el estado que creías tuyo puede SEGUIR** *(Xavier, 2026-08-29)*. No es higiene de git: es que **el estado que creías tuyo puede
haberlo movido otro mientras no estabas**, y arrancar sobre una foto vieja es empezar con una premisa haberlo movido otro mientras no estabas**, y arrancar sobre una foto vieja es empezar con una premisa
@ -1605,10 +1758,24 @@ de tres formas** —la sesión murió, se renombró, o **nunca fue una direcció
qué nombre la ven las demás)—. ⇒ **El único testigo válido de que una sesión murió es «escribí y no qué nombre la ven las demás)—. ⇒ **El único testigo válido de que una sesión murió es «escribí y no
contestó»**, jamás «no la veo en el listado». contestó»**, jamás «no la veo en el listado».
⛔ **Nada de LAVADO DE PERMISOS: si a una sesión le deniegan algo, no se lo pide a otra — lo devuelve
a quien la dirige.** No es doctrina de esta casa: es un modo de fallo **con nombre propio en el a quien la dirige.** No es doctrina de esta casa: es un modo de fallo **con nombre propio en el
contrato de la propia herramienta** (*cross-session permission laundering*). Un permiso que se contrato de la propia herramienta** (*cross-session permission laundering*). Un permiso que se
consigue rodeando a quien lo negó no es un permiso, y el canal hace ese rodeo trivial. consigue rodeando a quien lo negó no es un permiso, y el canal hace ese rodeo trivial.
⛔⛔ **DE `ListAgents` NO ES FIABLE NADA QUE PAREZCA UN IDENTIFICADOR ESTABLE: NI LA EDAD, NI EL
`[ref]`.** *(cicatriz `C-170`, medida por dos sesiones por separado.)* La **edad** dice **cuándo el
listado la vio**, no cuánto lleva viva — seis sesiones salieron como *«16 minutos»*, una de ellas
con **21 commits ese día**. Y el **`[ref]`** de una misma sesión **cambió sin reiniciar, mismo hilo
y mismo día** — siendo justo lo que la herramienta ofrece **para desambiguar**.
**Lo único que sirve es el NOMBRE en el momento de usarlo**, y **el único testigo de identidad son
los artefactos con hora** —commits, filas del semáforo— **más la respuesta de la propia sesión**.
⇒ ⭐ **Un `[ref]` se usa en el mismo turno en que se lee, y NUNCA se escribe donde sobreviva al
turno.** **Anotarlo en el semáforo es PEOR que no anotarlo**: le da a un identificador caduco **la
autoridad de una fila**, y las filas se leen como verdad.
⚠️ **Y el daño no es teórico**: con esa lectura, la superadmin estuvo a punto de declarar «otra
sesión» a la dueña de un frente y **dejar sus cuatro decisiones del día huérfanas en una tabla que
iba a las demás** — con otro frente pudiendo tomarlo por libre. **Lo deshizo la sesión aludida
enseñando sus commits con hora.**
**«Enviado con éxito» dice que el mensaje ENTRÓ EN LA COLA, no que alguien lo haya LEÍDO** — y su **«Enviado con éxito» dice que el mensaje ENTRÓ EN LA COLA, no que alguien lo haya LEÍDO** — y su
mitad simétrica, que es la que muerde: **el emisor tampoco sabe si su mensaje se CRUZÓ con el del mitad simétrica, que es la que muerde: **el emisor tampoco sabe si su mensaje se CRUZÓ con el del