diff --git a/.metodo/CHECKSUMS b/.metodo/CHECKSUMS index 32e35cb..7d90559 100644 --- a/.metodo/CHECKSUMS +++ b/.metodo/CHECKSUMS @@ -1,5 +1,5 @@ -0b309b932d65419946a6e9bfd7e39d164693789a90b4be75a6655c146d3fce84 metodo.md -71b3e3ace88ef15f0f18b3c0d7a4c5b6a340414a881042d0cc2bd4e8f2583d58 bin/metodo +960cba77494084b39c2291441ed63d090a03bd973701035a89b152597a289f32 metodo.md +17f68a7479044cc5b5557d53846839a85c8a1248db7f088431a0392302714dac bin/metodo f89b71bdf31028b05075636c1763c964e379bc37a00e0357d1c23a4dd19c09aa workflows/README.md cc241bbecf9647c747b8525b3a6b527455cd50ca0312caa44bc3544342c8ac41 workflows/comunicacion-entre-sesiones.md 2b9037f6dd57b5598c70a676cb728556654f05d1c5b024e7b716864659f7b884 workflows/sesion-ejecucion.md diff --git a/.metodo/bin/metodo b/.metodo/bin/metodo index 1b711a9..07e8c50 100644 --- a/.metodo/bin/metodo +++ b/.metodo/bin/metodo @@ -127,7 +127,7 @@ check_sesion_trailer() { 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; } 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 # 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 @@ -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. # ⇒ 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 - 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 </dev/null) 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)" + [ "$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" } @@ -595,6 +605,7 @@ check_commits() { # Formato de `.metodo/EXCEPCIONES` (del repo; NO se vendoriza — cada uno lleva las suyas): # C25 local excf="$ROOT/.metodo/EXCEPCIONES" exc_c=0 sha subj + local rec_c=0 _e while IFS=$'\t' read -r sha subj; do [ -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 @@ -603,8 +614,11 @@ check_commits() { fi bad "commit no-Conventional: \"$subj\" ($sha) (C25) — arréglalo, o decláralo en .metodo/EXCEPCIONES si ya está empujado" 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) [ "$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")" } diff --git a/.metodo/cicatrices.md b/.metodo/cicatrices.md index 2331c8d..6c9aae8 100644 --- a/.metodo/cicatrices.md +++ b/.metodo/cicatrices.md @@ -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 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 1–6 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. diff --git a/.metodo/metodo.md b/.metodo/metodo.md index 98f6c6a..22e02e9 100644 --- a/.metodo/metodo.md +++ b/.metodo/metodo.md @@ -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 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 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`)* @@ -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 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**. +⛔ **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 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ú.** + ⛔⛔ **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'' -- `**, + 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`)* @@ -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 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 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`)* @@ -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 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 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). @@ -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 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ú. + ⛔⛔ **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 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 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 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 @@ -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 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 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. + ⛔⛔ **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 *«1–6 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 mitad simétrica, que es la que muerde: **el emisor tampoco sabe si su mensaje se CRUZÓ con el del