diff --git a/.metodo/CHECKSUMS b/.metodo/CHECKSUMS index 06ebd24..128c5b0 100644 --- a/.metodo/CHECKSUMS +++ b/.metodo/CHECKSUMS @@ -1,5 +1,5 @@ -f226449c1039cca20dd14575fd26f6e5336e2d97e112e28a41a237ad1d1d84e2 metodo.md -36796ff4e2adf641dac48b4436a86ba75f99a919886b73e0b5266642a4b55634 bin/metodo +12ac115f5f7becf0f2490c6e5ad22b9588983319d953fb56a7172863169b4027 metodo.md +11bf48ad900c3a8748f229f4938a600ddd2a34897f36ee2284b10b5d44e3a0bf 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 cbb7c50..1610529 100644 --- a/.metodo/bin/metodo +++ b/.metodo/bin/metodo @@ -162,6 +162,32 @@ EOF # como el principio de otro párrafo. Ningún check miraba la integridad de la prosa. # ⇒ Testigo: una línea que acaba a mitad de frase (minúscula o coma) seguida de una que # ARRANCA un bloque nuevo (⛔ ⭐ ⚠️ ⇒ ⚙️ ⚰️ ✅, una cicatriz `*(`, o una cabecera `#`). +# ── C40: toda cicatriz referenciada existe, y ninguna sobra ──────────────────── +# ⛔ El corte regla/cicatriz (2026-09-02) mete una INDIRECCIÓN, y una indirección se +# pudre en silencio: un `C-047` citado que ya no existe se lee como una referencia +# normal, y una cicatriz huérfana no la echa de menos nadie. Los ids son PLANOS y no +# se renumeran nunca — decidido por Xavier: es mucho más resiliente que codificar la +# sección, que caduca al primer movimiento. +check_cicatrices() { + hdr "toda cicatriz referenciada existe (C40)" + local md cic + if [ -f "$ROOT/metodo.md" ] && [ -f "$ROOT/cicatrices.md" ]; then md="$ROOT/metodo.md"; cic="$ROOT/cicatrices.md" + elif [ -f "$ROOT/.metodo/metodo.md" ] && [ -f "$ROOT/.metodo/cicatrices.md" ]; then md="$ROOT/.metodo/metodo.md"; cic="$ROOT/.metodo/cicatrices.md" + else skip "no hay metodo.md + cicatrices.md que carear"; return 0; fi + local refs defs falta sobra dup + refs=$(grep -o 'C-[0-9]\{3\}' "$md" | sort -u) + defs=$(grep -o '^### C-[0-9]\{3\}' "$cic" | sed 's/^### //' | sort -u) + falta=$(comm -23 <(echo "$refs") <(echo "$defs") | tr '\n' ' ') + sobra=$(comm -13 <(echo "$refs") <(echo "$defs") | tr '\n' ' ') + dup=$(grep -o '^### C-[0-9]\{3\}' "$cic" | sort | uniq -d | tr '\n' ' ') + local mal=0 + [ -n "${falta// /}" ] && { bad "cicatriz(es) CITADAS y no definidas: $falta (C40) — la referencia se lee como normal y no lleva a ningún sitio"; mal=1; } + [ -n "${sobra// /}" ] && { bad "cicatriz(es) DEFINIDAS y no citadas: $sobra (C40) — huérfanas: nadie las echa de menos"; mal=1; } + [ -n "${dup// /}" ] && { bad "id(s) DUPLICADOS en cicatrices.md: $dup (C40) — un id se asigna una vez"; mal=1; } + [ "$mal" -eq 0 ] && ok "$(echo "$refs" | grep -c .) cicatriz(es), todas citadas y todas definidas" + return 0 +} + check_prosa_partida() { hdr "prosa cortada a mitad de frase (C39)" local f n @@ -976,6 +1002,10 @@ cmd_init() { mkdir -p "$md/bin" cp "$SELF_ROOT/metodo.md" "$md/metodo.md" cp "$SELF_ROOT/bin/metodo" "$md/bin/metodo"; chmod +x "$md/bin/metodo" 2>/dev/null || true + # Las CICATRICES viajan igual que la constitución (decidido por Xavier, 2026-09-02): el disco + # es gratis y el contexto no, así una sesión puede abrir la evidencia sin tener la matriz al + # lado. NO se lee por defecto — sólo cuando alguien discute una regla o quiere el dato crudo. + [ -f "$SELF_ROOT/cicatrices.md" ] && cp "$SELF_ROOT/cicatrices.md" "$md/cicatrices.md" # los workflows transversales viajan también (2026-08-29): un repo que se clona solo no # tiene la matriz al lado, así que un puntero a su ruta no le resuelve. El semáforo NO. mkdir -p "$md/workflows" @@ -1044,6 +1074,10 @@ cmd_update() { [ -d "$md" ] || { echo "metodo update: $tgt no tiene .metodo/ — usa 'metodo init $tgt'."; exit 2; } cp "$SELF_ROOT/metodo.md" "$md/metodo.md" cp "$SELF_ROOT/bin/metodo" "$md/bin/metodo"; chmod +x "$md/bin/metodo" 2>/dev/null || true + # Las CICATRICES viajan igual que la constitución (decidido por Xavier, 2026-09-02): el disco + # es gratis y el contexto no, así una sesión puede abrir la evidencia sin tener la matriz al + # lado. NO se lee por defecto — sólo cuando alguien discute una regla o quiere el dato crudo. + [ -f "$SELF_ROOT/cicatrices.md" ] && cp "$SELF_ROOT/cicatrices.md" "$md/cicatrices.md" # los workflows transversales viajan también (2026-08-29): un repo que se clona solo no # tiene la matriz al lado, así que un puntero a su ruta no le resuelve. El semáforo NO. mkdir -p "$md/workflows" @@ -1104,6 +1138,7 @@ cmd_check() { check_sesion_trailer check_incremento check_prosa_partida + check_cicatrices check_reparto_al_dia check_semaforo_forma check_semaforo_en_vuelo diff --git a/.metodo/metodo.md b/.metodo/metodo.md index fa162be..3dcdb78 100644 --- a/.metodo/metodo.md +++ b/.metodo/metodo.md @@ -28,12 +28,7 @@ doc en vez de repetirlo. No son teoría: cada uno lleva el caso real que lo ense > > ⛔ **Este fichero ES la fuente**, y vive en el repo `metodo` (la matriz). Se reparte con > `metodo update`, que lo copia byte a byte a `.metodo/metodo.md` de cada repo. **La copia no se -> edita nunca** (§7): se edita aquí y se re-estampa. *(Cutover 2026-08-19: hasta ese día la fuente -> era la copia del árbol de trabajo y esta constitución llevaba los 10 raíles base **en una línea**, -> con un puntero a una ruta que en un clon ajeno no existe. Coste medido: el raíl nuevo de §8 —«un -> fallo benigno solo protege si alguien LEE la línea»— nació el 2026-08-19 y **no estaba en ninguna -> de las 18 copias**. Ahora los raíles viajan COMPLETOS y las adiciones que estaban «pendientes de -> inlinar» viven dentro de su raíl.)* +> edita nunca** (§7): se edita aquí y se re-estampa. *(cicatriz `C-001`)* > Origen: destilados de la racha Hermes de julio 2026 (Fases 11/13, convergencia UI) **unificados > con el método ya afinado en los workflows del frente de aplicación** (el más maduro en método). La lección de @@ -67,8 +62,7 @@ barato**. Un componente que hay que defender porque cuesta reconstruirlo ya ha f en «tengo un problema». - ⭐ **Y la pregunta antes de aceptar cualquier mecanismo**: *¿esto sigue funcionando con **cien**?* Si la respuesta exige un gesto humano por instancia, no escala — y por `§0` **no vale**. - *(Familia de `A20`: la colisión de loopbacks era 1,9 % a 50 nodos y **26 % a 200**; lo que a escala - de banco es una anécdota, a escala de flota es el trabajo de una tarde.)* + *(cicatriz `C-002`)* ⚠️ **Y lo que NO cubre lo desechable, dicho una vez para que conste**: tirar un componente **no deshace lo que ese componente FIRMÓ o PUBLICÓ mientras estaba vivo**. Un artefacto firmado sobrevive @@ -106,10 +100,7 @@ PARA EL OPERADOR»). ⇒ ⛔ **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 -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 -que mis equipos de hoy **ni tienen**».)* La orquestadora evaluó `D25` —del **edge**, apartado +AMENAZA, y leerla fuera de su ámbito la hace parecer mala.** *(cicatriz `C-003`)* La orquestadora evaluó `D25` —del **edge**, apartado `E14`; ⚠️ **sigue sin entrada en su registro**, ver `A43` en el registro de avisos del edge, así que 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.** @@ -126,9 +117,7 @@ de la captura de hub), para que nadie lo confunda con un olvido. ⛔ **Y el refinement que lo hace ejecutable: una decisión que acarrea trabajo FUERA del alcance del producto o de la fase NO se queda como casilla.** Se convierte en **épica nueva** si es grande, o se va **a su fase** si tiene una — y se prioriza como todo lo demás: **por valor de producto**, no por -lo bien argumentada que esté. *(Xavier, `D7`, 2026-08-22. Estrenada el mismo día: `I11.11` salió de -su ficha a una épica propia **con su valor declarado — cero, porque no hay nadie esperándola**, que -es justo el dato que una casilla escondida dentro de otra ficha no da.)* +lo bien argumentada que esté. *(cicatriz `C-004`)* ⇒ Es el mismo movimiento que el del ámbito de amenaza, una capa más arriba: **lo que no es de aquí no se descarta ni se cuela — se muda, con su valor escrito.** @@ -139,10 +128,7 @@ no se descarta ni se cuela — se muda, con su valor escrito.** ⛔ **UN CENSO QUE SUBESTIMA ENTREGA UNA LISTA CORTA CON ASPECTO DE COMPLETA** — y eso es peor que no tenerla, porque **se cierra el tema**. Un censo que sobrestima chirría y se revisa; **uno que se queda corto se cree**. -*(Cicatriz 2026-09-01: un censo de dependencias filtraba **por pod**, y descartaba la línea entera si -el pod tenía **una** imagen ya pineada junto a las móviles ⇒ **dejó fuera el motor de la propia sesión -que lo estaba midiendo**. Lo cazó **sólo porque sabía que ese motor tenía que salir**. El mismo día, -un censo de tags móviles dio **4** y el bueno era **20**.)* +*(cicatriz `C-005`)* ⇒ ⭐ **El control es barato y no es «mirar otra vez»: mete en el censo un elemento que TIENE que aparecer, y compruébalo.** Si no sale, el filtro está mal — y lo sabes **antes** de entregar la lista. ⇒ Es el control positivo aplicado a una enumeración: sin él, **un censo no puede decirte que está @@ -157,14 +143,7 @@ volver a leerla — **volver a derivarla por otro camino**. 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ú.** -*(Medido 2026-08-31, y con recurrencia en dos frentes independientes. Un frente censó **sus once -errores del día** y cómo se cazó cada uno: **4** porque otro no estuvo de acuerdo · **2** por una -predicción escrita antes de medir · **2** por una anomalía del instrumento · **1** al re-derivar una -referencia justo antes de commitear · **1** por accidente. ⛔ **Cero releyendo su propio trabajo.** -El mismo día, quien lleva el Método contó **catorce** en su bitácora —un `awk` que no insertó nada, -un `--amend` que reescribió el commit de otra, un aviso falso dado en consola, un gate publicado -roto— y **también cero**: los cazaron **contar la aparición, el `push` rechazado, otra sesión -midiendo y el `--stat` del commit**. Todos externos.)* +*(cicatriz `C-006`)* ⛔ **Y la acotación que hay que llevar pegada, porque es la que hace honesta la medida**: ese censo **sólo contiene los errores que se llegaron a VER**. Los que no se cazaron **quedan fuera por @@ -192,39 +171,22 @@ heredada, un booleano cocinado o "el comando salió 0" no son prueba de la opera - ⛔ Antipatrón: "redes placebo" — dar por buena una operación por una señal que no la mide. ⭐ **Predice también lo que NO debe cambiar, y compruébalo.** Es lo que convierte un aviso en un -hecho. *(F11.13: meter una LAN en la malla «toca el firewall, como en F9.2 que tiró el acceso de -gestión». En vez de ir con cuidado, se **predijo** que el `md5` de `uci show firewall` no cambiaría -—solo `ospfd.conf` gana una línea `network`— y se midió antes y después: idéntico. El miedo pasó a -ser un invariante verificado.)* +hecho. *(cicatriz `C-007`)* ⛔ **Una partición se verifica por SUS DOS CARAS: lo que debe estar cerrado Y lo que debe estar abierto.** Comprobar solo la mitad cerrada **no distingue «bien particionado» de «todo roto»** — y -en autorización eso es peligrosísimo, porque el fallo se disfraza del resultado bueno. *(Cicatriz -2026-07-27: un segundo hub daba **401 en toda la administración** y parecía protegida. **No lo estaba: -estaba rota.** Su Ingress reclamaba `/api`, que una imagen pre-F1 no sirve, así que el catch-all -autenticado se tragaba también **`/links/pair`** — el mismo accidente que cerraba `/admin/pair` -impedía que **ningún device pudiera emparejarse**. Se vio al medir la cara abierta: `/links/pair` -pasó de `401` a **`422` con cuerpo de la aplicación**.)* +en autorización eso es peligrosísimo, porque el fallo se disfraza del resultado bueno. *(cicatriz `C-008`)* ⇒ Es la misma familia que *«un panel que muestra "nada" y uno que no puede ver nada se leen igual desde fuera»* (F10.3), aplicada a la autorización. **Un `401` no es una prueba de nada por sí solo.** ⛔ **Y la partición NO se razona sobre el enrutador: se DERIVA de lo montado, y discrimina por MÉTODO además de por ruta.** El guard corre **antes** de enrutar, así que no ve rutas — ve -**cadenas**. *(Cicatriz `R10`, 2026-07-28: la orquestadora afirmó «los espacios no chocan» mirando -el enrutador —el panel usa `/`, `/pending`, `/devices/…`; la API `/links/*`— y era cierto **para el -enrutador y falso para el guard**: `POST /devices/enroll` **casa con la plantilla** -`GET /devices/{device_id}`, que es una página del panel. Una lista pública por **prefijo** habría -abierto esa página a internet — el accidente del otro hub, en espejo: allí el catch-all cerró de más, -aquí habría abierto de más.)* ⇒ La lista de lo público se genera **del montaje real**, nunca de un +**cadenas**. *(cicatriz `C-009`)* ⇒ La lista de lo público se genera **del montaje real**, nunca de un razonamiento sobre qué prefijos «son de la API»; y `GET /x` y `POST /x` son **dos entradas distintas**. ⇒ ⛔ **Y su aplicación al DESPLIEGUE, que es donde más engaña: «¿existe esta ruta?» NO se contesta -con un código HTTP si delante hay un guard de sesión.** *(Cicatriz 2026-08-18: la orquestadora puso -como testigo estrella de un despliegue que `GET /crl/afirmar` pasara de **404** a **302/401**, y -escribió que sin esa comprobación *«un “desplegado” no distingue nada»*. Medido antes de usarlo: la -ruta **no daba 404 ni antes** —daba `303 → /login`— y `/zzz-inventada` daba **exactamente lo mismo**. -El testigo habría tomado el mismo valor con la pantalla puesta y sin ella.)* +con un código HTTP si delante hay un guard de sesión.** *(cicatriz `C-010`)* ⇒ **El testigo que sí discrimina es la TABLA DE RUTAS MONTADAS dentro del pod** —lo derivado del montaje, `R10` otra vez— y se lee **por el esquema OpenAPI, no recorriendo `app.routes` en plano**, que es la cicatriz `F11.11b` un piso más abajo: los routers incluidos van **anidados** y el recorrido @@ -240,16 +202,10 @@ repartiera otra cosa.)* Renueva la concesión —o espera el lease— **antes** midiendo el pasado. **Prefiere la prueba POSITIVA a la ausencia.** «No hay hits» es débil —puede ser una ventana corta, -un log rotado o un filtro mal puesto—; «el consumidor **se mudó**» es fuerte. *(F11.11b: en vez de -concluir que nadie llamaba al endpoint viejo, se enseñó que **el mismo device**, minutos después de -instalarse la versión nueva, pidió el endpoint nuevo con token y no volvió a tocar el viejo.)* +un log rotado o un filtro mal puesto—; «el consumidor **se mudó**» es fuerte. *(cicatriz `C-011`)* ⛔ **Si hay dos caminos que hacen lo mismo, el que prueban tus tests se conserva y el que usa el -usuario se pudre — y el andamio de los tests es justo lo que lo esconde.** *(Cicatriz 2026-07-27: -al ir a borrar el duplicado `/api/admin/*` apareció que las dos copias habían **derivado**, y la -correcta era **la que no llamaba nadie**. Desde el panel —la única puerta que usa un humano— -aprobar un nodo **no lo publicaba** hasta el barrido siguiente, y revocar una sede dejaba -resolviendo sus nombres **hasta 24 h**. Los tests iban por `/api/admin`, así que todo salía verde.)* +usuario se pudre — y el andamio de los tests es justo lo que lo esconde.** *(cicatriz `C-012`)* ⇒ **Borrar un duplicado es un MERGE, no una limpieza**: antes de tirar una copia, averigua cuál de las dos es la correcta y porta lo que falte. Y **haz que los tests entren por la puerta del usuario**, o seguirán certificando la copia equivocada. @@ -263,10 +219,7 @@ usuario**, o seguirán certificando la copia equivocada. ⛔ **Un artefacto que GATEA un build tiene que vivir DENTRO del contexto de ese build.** Si el gate lee un fichero que la imagen no incluye, no estás comprobando nada: estás comprobando tu árbol de -trabajo, que es justo lo que el gate existe para no creerse. *(Cicatriz `H35`, 2026-08-04, y salió -bien porque el build se puso ROJO: el censo de la superficie pública se escribió en `doc/`, fuera del -contexto `src/api` ⇒ dentro de la imagen **no existía**, `IndexError`, artefacto no pusheado. Se mudó -a `src/api/tests/` y en `doc/` quedó un puntero.)* +trabajo, que es justo lo que el gate existe para no creerse. *(cicatriz `C-013`)* ⇒ La pregunta antes de escribir cualquier fichero del que dependa una comprobación: **¿entra en la imagen?** Y su gemela, que es la buena noticia: **un gate que revienta porque le falta su insumo está funcionando** — el fallo silencioso habría sido que lo encontrara vacío y siguiera. @@ -287,51 +240,26 @@ veredicto **distinto** de «comprobado y verde» (y no admisible por defecto en **palabra** del veredicto codifica esa diferencia, no un campo lateral; una credencial acuñada prueba que **autentica** antes de `ready`. Pregunta única para cada señal: *«¿QUÉ tendría que estar roto para que esto se pusiera rojo, y ese estado PUEDE ocurrir de verdad?»* Si la respuesta es «no puede», es -una tautología. *(Cicatriz 2026-07-28, barrido de la colección MCP: la MISMA clase apareció en los -CUATRO — la rotación del MCP de secretos daba verde por una señal pegajosa + `kv_exists` [el path ya -existía]; el `version_matches` del MCP del edge comparaba el `.ipk` con su propio `control`; el -`mint_token(git)` no probaba que el token AUTENTICARA; el `verified-ok` del MCP de build daba verde con -los pods VIEJOS sirviendo `200`; su gate A3 admitía `ungated` por ausencia de gates. Dos se cazaron -por casualidad mirando otra cosa; el barrido encontró el resto. Dos de cuatro habría sido casualidad; -cuatro de cuatro es un raíl.)* +una tautología. *(cicatriz `C-014`)* -⛔ **Leer el código de TU capa no dice qué hace la capa de encima con tu salida.** *(Cicatriz `I8`, -2026-07-29: la ficha estimaba —leyendo `wg_hub.py`— que un re-alta anónimo dejaba el peer WG en pie -y que la pérdida llegaría «en el siguiente reinicio de `wg-hub`». **Son 36 segundos**: la API -reescribe `wg0.conf` sin ese peer, y `gre-sync` —**un script del chart, en OTRO repo**— borra el -`grehub` y con él la adyacencia OSPF. El peer sí sobrevivía; **moría todo lo construido encima**, y -eso convertía una bomba latente en una denegación de servicio en vivo.)* ⇒ Una predicción sacada de +⛔ **Leer el código de TU capa no dice qué hace la capa de encima con tu salida.** *(cicatriz `C-015`)* ⇒ Una predicción sacada de tu propio código describe **tu función**, no el sistema. Y con las capas repartidas entre repos, el que consume tu salida **no aparece en tu `grep`**: se mide, o se mide. ⛔ **Dos copias que coinciden entre sí no son una verificación — el aparato es el único que -desempata.** *(Cicatriz Fase 14, 2026-07-28: `transport-spec.md` daba la derivación v2 de la -loopback por «congelado ⏳» y describía la v1 —«la teclea el operador; el hub la asigna por -`peer_index`»— con las **dos mitades falsas**. Su espejo decía lo mismo, así que **leyendo docs era -indetectable**: solo el hardware llevaba la contraria, con `10.100.203.26` en el router de campo y -`10.100.255.154` en el hub. De la misma tirada cayó un problema que **la spec inventaba**: el puerto -WG no es «443 RUTOS / 51820 OpenWrt» sino `51234` de escucha en ambas, así que el conflicto de -despliegues mixtos que describía **no existe**.)* +desempata.** *(cicatriz `C-016`)* ⇒ Y la técnica que lo resolvió: **ejecuta el código INSTALADO, no lo reimplementes para comprobarlo.** Se corrió el módulo `wgt.overlay` del propio device; reimplementar el hash aquí habría verificado la reimplementación, no el sistema. -⛔ **Y el testigo tiene que ser independiente TAMBIÉN del acto de medir.** *(Cicatriz `P9c`, -2026-07-28: el panel comprobaba si `zebra` corría buscándolo en `ps` — y la contraseña del VTY de -quagga **es `zebra`**, así que **cada sonda dejaba en `ps` un proceso propio que casaba**. El módulo -se veía a sí mismo: cuanto más se miraba el panel, más imposible era que arrancara.)* Una sonda que +⛔ **Y el testigo tiene que ser independiente TAMBIÉN del acto de medir.** *(cicatriz `C-017`)* Una sonda que casa con su propia invocación no mide el sistema, **te mide a ti mirándolo**. Señal de alarma: un observable que **mejora cuando lo consultas** — y, en general, cualquier comprobación por `ps`/`grep` sobre una cadena que también aparece en el comando que la busca. ⛔ **Un testigo que no puede ponerse ROJO no es un testigo — y el que se pone rojo SIEMPRE mata lo que venía a proteger.** Si la señal que esperas la produce una capa **DELANTE** de lo que verificas, -no está mirando tu sistema: está mirando al portero. *(Cicatriz `engine`, 2026-07-30, cazada **antes -de armarla**: el `verify` del MCP de build sale por internet y el Ingress de `engine` tiene whitelist de -IP ⇒ devuelve **403 pase lo que pase**. Un `expect_status:200` habría fallado **siempre** → auto- -rollback → re-pin del digest anterior, que daba **404** → `engine` muerto y sin vuelta atrás: el -mecanismo de seguridad era el asesino. Y `expect_status:403` es **peor**: el ingress-controller -devuelve 403 **aunque el pod esté en `ImagePullBackOff`** — verde eterno sobre un servicio caído.)* +no está mirando tu sistema: está mirando al portero. *(cicatriz `C-018`)* ⇒ Antes de elegir el valor esperado, pregunta **quién lo produce**. Si lo produce el proxy, el firewall o el balanceador, cámbialo por uno que solo pueda salir **de dentro**. Y si no hay ninguno alcanzable, la respuesta correcta es **la palabra degradada** (`deployed-unverified`) más una @@ -344,11 +272,7 @@ ignorar los rojos**, y el siguiente será de verdad. Un sondeo que puede caer en ⛔ **Cuando una sonda te engaña, el arreglo es OTRO OBSERVABLE — no más reintentos.** Reintentar sobre un valor que el propio sujeto escribe solo es **esperar a que la tautología se complete**. -*(Cicatriz `A16`, 2026-08-01: el MCP del edge leía la versión con `head -1` —**por posición**— y -`/api/settings` tenía **dos claves `version`**; se quedaba con la del **install-report, un fichero que -escribe el `postinst` del propio `.ipk`**. Resultado: `installed 2.1.58 · served 2.1.58 · HTTP 200 · -4/4 enabled`, **verde entero, con el panel ejecutando 2.1.57**. El arreglo no fue reintentar: fue -esperar a **la marca de fin del instalador**, que es un observable distinto del que gatea.)* +*(cicatriz `C-019`)* ⇒ Dos formas concretas de caer, las dos vistas: - **Leer por POSICIÓN y no por NOMBRE**: `head -1`, `[0]`, «el primer campo que casa». El día que aparece un segundo valor con el mismo nombre, gana el que no querías **y nadie se entera**. @@ -356,40 +280,22 @@ esperar a **la marca de fin del instalador**, que es un observable distinto del repite lo que le inyectaron, un `ps` que casa con tu propia invocación. - ⭐ **Usar un cliente que SIGUE REDIRECCIONES, y leer el destino como si fuera el origen.** Un guard que redirige a `/login` es indistinguible de *«no hay guard»* si tu herramienta te da el - `200` del final del camino. *(Cicatriz 2026-08-13, y la cometió la orquestadora: midió el panel - del hub del trabajo con `urllib.request.urlopen` —que sigue los `3xx` por defecto y no lo dice— y - concluyó **«la aplicación no comprueba nada, el panel está abierto dentro del cluster»**. Era - falso: contestaba `303 → /login`. Encima **tumbó un hallazgo correcto** de la sesión de - ejecución —que sí había medido con `wget -S`, que enseña la traza entera— y estuvo a punto de - cambiar el motivo de una decisión por uno inventado.)* ⇒ Cuando midas una autorización, **exige + `200` del final del camino. *(cicatriz `C-020`)* ⇒ Cuando midas una autorización, **exige ver la traza**: el código de CADA salto y sus cabeceras. Y desconfía por defecto de todo cliente que «te lo pone fácil» — `urlopen`, `requests.get`, un navegador: la comodidad es exactamente lo que te esconde el peldaño que estabas midiendo. -- ⭐ **Preguntar por un NOMBRE que resuelve distinto según quién pregunta.** *(Cicatriz `H12`, - 2026-08-02: `harbor.manabo.org` es **Valhalla** desde el constructor y **Athena** desde los nodos - que tiran. Una sonda de «¿ya está la imagen?» lanzada desde el pod habría preguntado **al registro - que acababa de recibir el push** ⇒ **200 siempre**. Por eso el destino de la sonda tiene que ser un - **endpoint explícito**, no el nombre.)* Si un nombre es split-horizon, **no sirve como dirección de +- ⭐ **Preguntar por un NOMBRE que resuelve distinto según quién pregunta.** *(cicatriz `C-021`)* Si un nombre es split-horizon, **no sirve como dirección de un testigo**: solo sirve para hablar, no para comprobar. ⛔ **En un reconciliador, «lo que yo no escribo» NO es «lo que sobra».** El conjunto que **enumeras** para decidir qué conservar tiene que ser **más ancho** que el que **escribes** — reutilizar el filtro -estrecho convierte *«esto no lo gestiono yo»* en *«esto se borra»*. *(Cicatriz evitada el 2026-08-02 -construyendo la poda de `allowed-ips`: el peer `yomi` lo pone `wg-setup` **desde un Secret** y el API -**nunca** lo escribe en la conf. Una poda de «borro todo lo que no reconozco» se lo habría llevado — -que es el error de `H13` con el `lo` del nodo, y por eso hizo falta una lista `PRESERVE_PEERS` -explícita.)* +estrecho convierte *«esto no lo gestiono yo»* en *«esto se borra»*. *(cicatriz `C-022`)* ⇒ Antes de escribir una poda, pregunta: **¿quién MÁS escribe aquí?** Un recurso compartido casi siempre tiene más de un dueño, y el que no ves es el que vas a romper. ⇒ Y su gemelo: **si la lectura del estado vivo FALLA, no se poda nada.** Un `wg show` que no responde devuelve **ausencia**, no **conjunto vacío** — y tratarlos igual borra la instalación entera. ⇒ ⛔ **Y esto también le pasa a Kubernetes, así que no lo des por resuelto porque lo haga el -sistema.** *(Cicatriz 2026-08-02: un `kubectl delete ns karmada-system` lanzado con el plano de -control revuelto por los reinicios de esa misma sesión —`connection refused` contra el apiserver a la -misma hora— se llevó el objeto `Namespace` y dejó **vivos los 18 objetos de dentro**, listables y sin -`deletionTimestamp`, en un namespace que ya no existía. El `namespace-controller` **enumera por -discovery** lo que debe borrar; una enumeración vacía se leyó como «no queda nada», retiró el -finalizador y el `Namespace` desapareció antes que su contenido.)* +sistema.** *(cicatriz `C-023`)* ⇒ ⭐ **Y lo que lo hace peligroso no es el huérfano, es que sea INVISIBLE**: casi todo se audita **por namespace**, y ese namespace ya no está. Es la cicatriz de kaniko en variante nueva — *quitar el gestor no quita lo gestionado*. @@ -399,11 +305,7 @@ empezar o **después** de comprobar que los apiservers responden — y la compro que el contenedor padre ya no esté: es que **los objetos ya no están**, incluidos los *cluster-scoped*. ⛔ **De un contador se deduce TRÁFICO, no PROPÓSITO. «Nadie lo usa» no es una medida: es una -inferencia — y es la que justifica retirar cosas.** *(Cicatriz 2026-08-02, cazada por Xavier antes de -ejecutarse: un aviso describía un `wg0` con **RX 0 y TX 56 MiB** como «un túnel muerto que nadie -usa», y la orquestadora ofreció «levantarlo o quitarlo» como dos opciones equivalentes. Xavier: -**«ese túnel es con el que me conecto yo a casa»** — y estaba **fuera de casa** en ese momento. -Quitarlo le habría cortado el acceso.)* +inferencia — y es la que justifica retirar cosas.** *(cicatriz `C-024`)* ⇒ ⭐ **Y el caso peor es sistemático: un camino de último recurso parece ocioso PORQUE funciona.** Solo se usa el día que hace falta, así que «sin tráfico» es su estado normal — y es justo lo que lo hace parecer muerto. Acceso de emergencia, rutas de respaldo, credenciales de rescate: todas se ven @@ -412,17 +314,11 @@ igual que la basura. escribió una sesión que solo vio contadores, **la propuesta de retirada no está fundada**: lo que midió es que no pasa tráfico, no que no sirva. -⛔ **Un testigo que no DISCRIMINA es peor que no tener testigo**, porque da permiso. *(El mismo -`A16`: se propuso «comprobar que el PID cambió» como prueba de reemplazo — y **el respawn de procd -también estrena PID**, así que habría salido verde sobre el árbol viejo. El testigo bueno era **la -versión que el panel SIRVE**, que es lo único que solo puede decir el árbol que corre.)* +⛔ **Un testigo que no DISCRIMINA es peor que no tener testigo**, porque da permiso. *(cicatriz `C-025`)* ⇒ Antes de aceptar un testigo, pregunta: **¿qué valor tomaría si el fallo estuviera presente?** Si es el mismo, no es un testigo: es un adorno. ⇒ ⭐ **Y el caso más común de todos: una alerta construida sobre «¿responde?» no puede distinguir -«el sujeto está caído» de «mi sonda está rota».** *(Cicatriz 2026-08-02, cluster `home`: dos reglas -—`etcdMembersDown` y `etcdInsufficientMembers`— contaban **targets de scrape** y los llamaban -«miembros». Llevaban **56 días** en rojo porque los cuatro componentes del plano de control escuchaban -sus métricas en `127.0.0.1`, con los cuatro **perfectamente sanos**.)* Lo que lo demostró **no fue +«el sujeto está caído» de «mi sonda está rota».** *(cicatriz `C-026`)* Lo que lo demostró **no fue razonarlo, fue un banco de usar y tirar**: tres etcd de juguete, **matando 2 de 3** — y el superviviente **siguió sirviendo `/metrics`**, o sea que `up` se habría quedado en **1**. Lo que sí se movió fue el estado interno (`etcd_server_has_leader` 1→0, `peer_sent_failures` 0→16→95). @@ -432,11 +328,7 @@ mueve**. Si la tuya no se mueve, tu alerta no vigila lo que crees. ⛔ **Un campo de `status` que suena a «lo que hay AHORA» puede ser «lo que había la última vez que el controlador lo tocó» — y creerse ese nombre lleva a arreglar la declaración en vez del sistema.** -*(Cicatriz 2026-08-02, y la cometió la orquestadora: dedujo que Vault llevaba «29 días corriendo sin -el `hostAliases`» porque `currentRevision ≠ updateRevision`, y recomendó **revertirlo en git para que -la alerta se apagara sola**. Medido en el aparato: hay **12** ControllerRevisions, el pod corre la -**10**, `currentRevision` apunta a la **4** y el deseado es la **12**. Con `updateStrategy: OnDelete` -ese campo no describe nada real, y el pod **sí** llevaba el `hostAliases` — en su `/etc/hosts`.)* +*(cicatriz `C-027`)* ⇒ El testigo de qué corre es **la etiqueta del propio pod** (`controller-revision-hash`), o su `/etc/hosts`: se mide en el sujeto, no en la opinión del controlador. ⇒ ⭐ **Y el corolario general, que es el peligroso: cuando una alerta compara DESEADO con ACTUAL, la @@ -448,55 +340,33 @@ editar la intención hasta que cuadre. ⇒ ⛔ **Y su espejo, que engaña en la dirección que NADIE vigila: un estado de ERROR es tan pegajoso como uno verde.** De un verde heredado ya desconfiamos; un **rojo** heredado se lee como *«sigue -roto»* — y eso hace perseguir un problema **ya resuelto** y «arreglar» lo que estaba bien. *(Cicatriz -2026-08-12: repuesto el token de ESO de `hermes`, **20 de 30 `ExternalSecret` seguían en -`SecretSyncedError`** y la lectura obvia era «no funcionó»; se estuvo a un paso de reiniciar ESO y de -reescribir la política. Lo que lo desmintió fue **la HORA del último error en el log: siete minutos -de silencio**. El campo contaba el ciclo anterior — su `refreshInterval` es de **una hora**. Forzando -el refresco de los treinta: **30/30 verdes**.)* +roto»* — y eso hace perseguir un problema **ya resuelto** y «arreglar» lo que estaba bien. *(cicatriz `C-028`)* ⇒ El `status` de un objeto narra **su última reconciliación**, no el presente — en los dos colores. Para saber si algo sigue roto: mira **cuándo** fue el último fallo, o **provoca** la reconciliación. Nunca leas el campo y ya. ⛔ **Cuando el riesgo es una PÉRDIDA SILENCIOSA, el testigo tiene que ser DIFFEABLE.** Una comparación que solo puede hacer un humano mirando siempre concluye *«se ve igual»* — y esa es -exactamente la conclusión que el riesgo necesita para pasar. *(Cicatriz al revés, 2026-08-01, hecho -BIEN: vaciando de texto las pantallas de dos paneles, el peligro era llevarse **estado** junto con los -comentarios. En vez de capturas —que **no se pueden diffear**— se volcó **el texto de todas las -pantallas antes y después** en los dos aparatos, con un clasificador prosa/medida: **0 medidas -cambiadas**, y los únicos cambios fueron los seis textos que se querían mover.)* +exactamente la conclusión que el riesgo necesita para pasar. *(cicatriz `C-029`)* ⇒ Antes de una poda, un refactor o una migración, pregunta: **¿qué artefacto puedo comparar a máquina?** Si la respuesta es «ninguno», invéntalo **antes** de tocar — un volcado, un censo, un hash. Lo que no se puede diffear no se puede echar de menos. ⇒ ⭐ **Y el corolario que justifica el gasto: «COSMÉTICO» NO ES UNA CATEGORÍA DEL SISTEMA, ES UNA CATEGORÍA TUYA.** Tú decides que un cambio no toca nada; el artefacto no comparte tus categorías, y -un testigo diffeable es lo único que os pone de acuerdo. *(Cicatriz 2026-08-13, y salió BIEN: una -sesión documentó el porqué de una perilla con comentarios `#`… **dentro de `spec:`**, o sea que -salen en el render. El gate de bytes se puso **rojo en los tres hubs vivos sin que cambiara un solo -valor**. Pasaron a `{{/* */}}` y volvieron los bytes exactos. Sus palabras: «el gate se ganó el -sueldo en el cambio que yo habría llamado cosmético».)* +un testigo diffeable es lo único que os pone de acuerdo. *(cicatriz `C-030`)* ⇒ Por eso un gate de artefacto **no se salta «porque esto solo es un comentario»**: si de verdad no cambia nada, pasa solo y no cuesta; y si cuesta, es que cambiaba algo. -⇒ ⛔ **Pero un hash de algo GENERADO solo vale si el generador es determinista.** *(Cicatriz `F12.1`, -2026-08-02: se eligió el `md5` de `ospfd.conf` como testigo de *«esto no ha cambiado»*, y el fichero -lo escribe un bucle sobre `pairs()` de Lua, que **no ordena**. El hash bailaba sin que cambiara una -sola línea ⇒ el testigo habría gritado en cada medida, y a la tercera nadie se lo cree.)* El arreglo +⇒ ⛔ **Pero un hash de algo GENERADO solo vale si el generador es determinista.** *(cicatriz `C-031`)* El arreglo no es cambiar de testigo: es **normalizar antes de comparar** (ordenar) — y entonces el diff vuelve a significar algo, que es como se cerró la desistencia: `ospfd.conf` **idéntico al byte**, ordenado. ⇒ Pregunta previa a usar un hash: **¿dos ejecuciones sin cambios dan el mismo byte?** Si no lo has comprobado, no tienes un testigo, tienes un generador de ruido. ⇒ ⛔ **Y aunque normalices: guarda el ARTEFACTO, no su huella.** Un hash dice **que** algo cambió y -**nunca qué** — así que el día que se mueve estás ciego justo cuando necesitas mirar. *(Cicatriz -`E9`, 2026-08-03, y es la segunda vez en dos días: el `md5` de un `ospfd.conf` se movió, la sesión -pudo demostrar por reconstrucción que no era suya… pero **no pudo diffearlo**, porque había guardado -el hash y no el contenido normalizado.)* Un hash cuesta 32 bytes y un fichero de configuración cuesta +**nunca qué** — así que el día que se mueve estás ciego justo cuando necesitas mirar. *(cicatriz `C-032`)* Un hash cuesta 32 bytes y un fichero de configuración cuesta dos kilos: **no hay ninguna razón para guardar el resumen en vez del original.** ⛔ **Una carrera no se ESPERA: se PROVOCA.** Si el fallo depende de coincidir con un bucle, cronometrar -es un sorteo — y tres «no apareció» seguidos no dicen nada. *(Cicatriz `H24`, 2026-07-31: la ventana -del zombi no era de 10 s fijos, iba de **~0 a ~10 s** según dónde cayera el revoke dentro del -`sleep 10` de `pq-sync`; con la rotación de Rosenpass en 131 s, acertar era un **~8%**. Tres intentos -fallaron por 50 s, 3 s y 1 s.)* +es un sorteo — y tres «no apareció» seguidos no dicen nada. *(cicatriz `C-033`)* ⇒ Lo que lo hizo repetible: **dejar de cronometrar y disparar el intercambio**, y **calcular la fase del bucle a partir del `T0` que el propio supervisor escribe en su log** — el sistema suele publicar su reloj; úsalo en vez de adivinarlo desde fuera. @@ -506,10 +376,7 @@ evidencia** — es la misma medida sin discriminación. ⛔ **Una nota de cierre tiene que nombrar QUÉ COPIA cerró.** «Arreglado en `hermes`» no dice si habla del **código**, de la **imagen** o de la **instancia que corre** — y son tres cosas distintas que se -desincronizan solas. *(Cicatriz `H16`, 2026-07-30, y es la **tercera** reincidencia de `H6` — -casillas rancias— tras el 26 y el 27 de julio. El modo de fallo nuevo: la casilla no se podía -contradecir **leyendo los docs**; hubo que entrar en el contenedor a comparar `sha256sum` contra -`git show HEAD:`.)* +desincronizan solas. *(cicatriz `C-034`)* ⇒ Y el testigo se elige por quién lo produce: **`/health` NO sirve** — devuelve el string que le inyectó el `values`, o sea un auto-informe. Lo que decide es el `imageID` del contenedor (qué se empaquetó) y, mejor aún, **una huella que solo pueda haber escrito el camino de código nuevo** (una @@ -518,11 +385,7 @@ corrió**. ⛔ **Y el caso más traicionero: un artefacto producido por el CÓDIGO DEFECTUOSO no prueba nada sobre el estado que ese defecto ignoraba.** Si el fallo consiste en *«no mirar X»*, entonces lo que ese código escribe sale **igual valga X lo que valga** — así que leer su salida para deducir X es -leer el defecto y llamarlo dato. *(Cicatriz 2026-08-03, y la cometió la orquestadora: dedujo que una -LAN estaba en la malla porque el fichero de opciones DHCP existía. Cierto con el código de hoy —que -solo lo escribe para las LAN de la malla— y **falso con el que corría cuando lo midió**, que lo -escribía **incondicionalmente y sin consultar el eje**. La existencia del fichero probaba justo lo -contrario: que el eje se ignoraba.)* +leer el defecto y llamarlo dato. *(cicatriz `C-035`)* ⇒ ⭐ **Y arreglar el defecto cambia el significado de la evidencia hacia atrás.** Antes de inferir estado de un artefacto, pregunta **qué versión lo escribió y si esa versión miraba lo que quieres deducir**. Si no lo miraba, el artefacto es un testigo de la avería, no del sistema. @@ -535,20 +398,14 @@ deducir**. Si no lo miraba, el artefacto es un testigo de la avería, no del sis sobre el repo, **mide sobre `origin/`**, no sobre lo que tienes delante. ⇒ ⛔ **Y AL REVÉS, que es el que no se espera: medir el ARTEFACTO correcto puede esconder que la COPIA que usa la gente está rota.** Son dos preguntas distintas —*«¿qué despliega ArgoCD?»* y - *«¿qué le pasa a quien clona esto?»*— y **ninguna receta contesta las dos**. *(Cicatriz - 2026-08-06: `pq-secret.sh` estaba en **CRLF en el worktree** y así ni arranca —`set -uo - pipefail\r`—, o sea que con `core.autocrlf=true` un clon en Windows deja **todos** los bancos - muertos. El censo no lo vio porque medía —bien— sobre un `git archive` en LF: **la receta correcta - tapó el defecto que la rodeaba**. Se cosió con un `.gitattributes`.)* ⇒ Cuando elijas dónde medir, + *«¿qué le pasa a quien clona esto?»*— y **ninguna receta contesta las dos**. *(cicatriz `C-036`)* ⇒ Cuando elijas dónde medir, di **qué pregunta estás contestando**; y si la herramienta tiene una salida de emergencia (un `tr -d '\r'`, un fallback), pregúntate **qué está haciendo tolerable que no deberías tolerar**. ⛔ **Y EL TESTIGO DE EOL HAY QUE VALIDARLO CON UN FICHERO QUE SEPAS QUE ES CRLF, porque el obvio MIENTE.** `grep -c $'\r'` **es ciego al CR en algunos shells**: devuelve **0** sobre un fichero que `od -c` demuestra lleno de `\r\n`. ⇒ Y lo peor: **acertó tres veces seguidas antes de fallar** — los tres ficheros eran LF de verdad. *Lo que funciona por casualidad está roto*, aplicado a un testigo. -*(Cicatriz 2026-09-01. Se destapó porque un `git diff` marcaba **48 líneas cambiadas** donde el cambio -real eran **13**, con líneas idénticas en `-` y `+`. Y el segundo intento también mintió: daba **9733 -CR en 268 líneas**, un número imposible **que sólo se ve si compruebas la aritmética**.)* +*(cicatriz `C-037`)* ⇒ **Lo que discrimina**: `od -c`, o `tr -dc '\r' | wc -c`. **Nunca `grep $'\r'`.** Y **guarda un fichero CRLF conocido** como control positivo del testigo. - **Si un inventario lista dos medidas del mismo día, la hora es parte del dato.** Un robot @@ -556,12 +413,7 @@ fichero CRLF conocido** como control positivo del testigo. un después**, y tratarlo como conflicto te hace corregir dos veces y acertar ninguna. ⛔ **Si delegas una decisión en el operador, TIENES QUE DARLE EL GESTO. Si no, no has delegado: has -cerrado la puerta.** *(Cicatriz `H23`, 2026-07-31: `I1` decidió —bien— que re-admitir a un nodo -revocado es **«una autorización NUEVA del operador»**… y construyó solo la **negativa**. Medido en el -pod que corre: `POST /links/pair` da **403** permanente, `approve_pair` exige `pending`, y **ninguna -pantalla pinta una fila revocada** ⇒ **no hay botón que pulsar**. Hubo que tocar `status` en la base -de datos. Y lo que lo vuelve grave: el procedimiento documentado de `H21` dice **«revoca los edges -antes de renombrar un hub»** — seguirlo en el cliente dejaría sus sedes fuera **sin marcha atrás**.)* +cerrado la puerta.** *(cicatriz `C-038`)* ⇒ Prueba barata, y hazla al diseñar, no al depurar: **para cada estado en el que tu sistema puede entrar, ¿cuál es la salida y quién la pulsa?** Un control que solo se puede **aplicar** y nunca deshacer no es un control, es una trampa. Y si el estado terminal no aparece en ninguna pantalla, @@ -569,12 +421,7 @@ para el operador **no existe** — da igual lo que diga la fila en la base de da ⛔ **Un identificador que además es CLAVE DE BÚSQUEDA no se puede renombrar: sepáralo antes.** Si un mismo valor da el nombre público **y** direcciona secretos, rutas o etiquetas, cambiar la cara -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"` -no recortaba nada y el hub habría ido a buscar su clave WireGuard y su **clave Rosenpass** —la que -la `D100` del hub prohíbe regenerar; era `F13·D10` hasta que el 2026-08-22 se renumeró al -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.)* +visible **re-direcciona lo invisible**, y en silencio. *(cicatriz `C-039`)* ⇒ 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 tenga formato obligado (una etiqueta de kernel, un path), **que la plantilla falle al renderizar** — @@ -582,11 +429,7 @@ probado que falla, no supuesto. ⛔ **Un comentario que JUSTIFICA saltarse una puerta sobrevive al motivo, y convierte el bypass en rutina.** Es el peor sitio donde se puede pudrir una nota: el resto de la documentación rancia hace -perder el tiempo; ésta **desarma un gate y encima explica por qué está bien**. *(Cicatriz 2026-07-30: -el catálogo del MCP de build llevaba un CAVEAT diciendo que la suite del hub estaba -obsoleta —12/28 en rojo— y que por eso «el deploy se valida con `skip_tests`, bypass **auditado**». -Había dejado de ser cierto el **2026-07-24**: las 12 aserciones se reescribieron y la suite va a -**90 passed**. Seis días en los que la razón ya no existía y el permiso seguía escrito.)* +perder el tiempo; ésta **desarma un gate y encima explica por qué está bien**. *(cicatriz `C-040`)* ⇒ Toda excusa escrita para desactivar una comprobación **nace con fecha de caducidad**: dice qué la justifica y **qué la cancelaría**. Y quien arregla la causa tiene que borrar el permiso — si no, lo que queda no es una excepción, es la nueva costumbre. @@ -594,11 +437,7 @@ que queda no es una excepción, es la nueva costumbre. ⛔ **Y su hermano, que es peor porque parece inofensivo: un PENDIENTE rancio no es ruido, es una INSTRUCCIÓN EQUIVOCADA esperando a que alguien la ejecute.** Una casilla `[ ]` no solo describe un problema: casi siempre trae **cómo arreglarlo**, y ese «cómo» está anclado al diseño de cuando se -escribió. *(Cicatriz 2026-08-04: bajo una cabecera marcada ✅ sobrevivía un pendiente sobre una -carrera `revoke + enroll` **que `I1` había vuelto inconstruible** —los dos `db.delete` ya no -existen—, y su arreglo propuesto era *«un SELECT+DELETE atómico»*. Quien lo hubiera cogido de buena -fe habría **reintroducido exactamente lo que `I1` quitó**, que era el borrado de la fila y toda la -vulnerabilidad con él.)* +escribió. *(cicatriz `C-041`)* ⇒ **Al cerrar algo, barre los pendientes que describían su arreglo**: desde ese momento describen el arreglo **equivocado**. Cerrar una decisión sin barrer su cola deja instrucciones armadas. @@ -623,11 +462,7 @@ siguen vivos sin ella**. Y la comprobación de un desmontaje no es «la Applicat ⛔ **Y borrando DOCUMENTOS pasa lo mismo, con una moneda peor: antes de retirar un documento de estado, cuenta lo que está ABIERTO en él — no sus ids, no sus líneas.** Ids y líneas miden **tamaño**; las casillas `[ ]` miden **obligaciones**, y son lo único que no se puede reconstruir después. -*(Cicatriz 2026-08-03, y la cazó la propia sesión al aplicar su propuesta, no la propuesta: al retirar -`BACKLOG-HERMES.md` —826 líneas, con el invariante de ids comprobado y cuadrado— quedaban **cuatro -ítems abiertos de la red del trabajo** que el borrado se habría llevado **en silencio**: excluir una -IP de la pool de MetalLB, identificar físicamente al okupa de un puerto de switch, renombrar un -address-object del firewall y un puerto de destino. Nada de eso tenía id; eran casillas.)* +*(cicatriz `C-042`)* ⇒ El censo previo a un borrado tiene **dos columnas**: qué ids se van *(y a dónde)* **y qué queda sin hacer** *(y a qué backlog se muda)*. La segunda es la que salva trabajo; la primera solo salva referencias. @@ -638,10 +473,7 @@ comentarios. ⛔ **La réplica PROPAGA la decisión, no la juzga: una réplica fiel de una decisión mala la hace global.** Mejorar el mecanismo que distribuye, sobre un procedimiento que decide mal, **no arregla — -amplifica**. *(Cicatriz `A20`, 2026-08-01: la `/32` que un hub se inventó al resolver una colisión no -se quedó ahí — el edge la adoptó (`A17`), la re-declaró al otro hub (`A18`), que la aceptó, y el -nombre del router acabó resolviendo a la dirección equivocada **por los dos caminos**. Cuanto mejor -funcionaba la réplica, más lejos llegaba el error.)* +amplifica**. *(cicatriz `C-043`)* ⇒ Antes de mejorar una distribución, pregunta **quién decide lo que se distribuye**. Si el generador puede equivocarse, la respuesta no es replicar mejor: es **quitarle la decisión** — el arreglo fue que el hub dejara de asignar, no que asignara con más cuidado. @@ -672,14 +504,7 @@ se sabe que sirve. CONCLUSIÓN FALSA CON ASPECTO DE MEDIDA.** Es el fallo de la **juntura**, y hoy no lo caza ningún otro raíl: `§5` dice *no inventes lo no medido* y arriba está *verifica el resultado, no la intención* — pero aquí **nadie inventa nada y todo lo afirmado está medido**. Lo que falla es **unirlo**. -*(Cicatriz 2026-08-28, y es la única del día que llegó a mover el orden de trabajo del usuario: un -aviso reclamaba un gesto urgente sobre la BIOS de un servidor —«la carga está armada»— y desplazó -cuatro asuntos. Un frente había medido **la conducta del SERVICIO** —un host declarado se sirve sin -menú, y el arranque por red instala solo a los 30 s— **y era cierto**. Nadie midió la **precondición**, -que es de **otro sujeto**: el orden de arranque de la **MÁQUINA**. Lo refutó el usuario en una frase: -para arrancar por red **hay que pulsar una tecla**; el disco ya era el primero. La conclusión -compuesta había viajado con fecha, contra-medidas y hasta un `User-Agent` —**todos los signos -externos de una medida**— y **tres registros la aceptaron sin pedirle la precondición**.)* +*(cicatriz `C-044`)* ⇒ **Regla**: cuando una conclusión **cruza dos sujetos** —un servicio y una máquina, un repo y un cluster, un motor y el hierro que lo arranca—, **cada sujeto necesita SU PROPIA medida**. Heredar la solidez de uno para el otro es **cómo se fabrica una alarma falsa con pinta de dato**. @@ -692,11 +517,7 @@ frentes por separado, y uno de ellos ya se había pasado de frenada al corregir. ⛔ **UN TESTIGO SIN FUENTE NOMBRADA NO ES VERIFICABLE AUNQUE SEA CIERTO — y lo caza quien intenta REPRODUCIRLO, no quien duda de él.** El fichero, el endpoint o el comando exacto va **DENTRO del -testigo**, no en la cabeza de quien lo midió. *(Dos frentes independientes el 2026-08-28, con casos -distintos. Uno: dos sesiones afirmaban cosas **opuestas** sobre «el log del motor» — y no era un -objeto, eran **dos**, uno por stdout **sin `User-Agent`** y otro dentro del mismo pod en formato -combinado; **ninguna se equivocaba sobre su fuente, faltaba nombrarla**, y lo destapó que una -intentara reproducir el testigo de la otra y no pudiera.)* +testigo**, no en la cabeza de quien lo midió. *(cicatriz `C-045`)* ⇒ ⭐ Y el patrón que lo generaliza, con **cuatro instancias en tres frentes el mismo día**, todas de la misma forma: **el instrumento no decía de qué estaba hablando.** El log no decía **quién**; un `uptime` no decía **cuándo** —se leyó una máquina catorce minutos antes de que terminara su @@ -738,23 +559,13 @@ la anunciada**. Y el verde que devuelve es cierto: contesta **otra pregunta**. T medidas el 2026-09-02: **① PRESENCIA en lugar de FORMA.** Comprobar que algo *está* no comprueba que esté *bien puesto*, y -el testigo de presencia **sale verde en los dos casos**. *(**(a)** un bloque de 14 líneas insertado -con `sed a\` entró **colapsado en UNA sola línea**; el testigo era `grep -c ` → **1**, -verde, con la forma destruida. El bueno era `git diff --numstat` (15) junto a `grep -c '^+>'` (14). -**(b)** filtrar un diff con `grep "^[+-][^+-]"` **oculta toda línea de lista Markdown** —una viñeta -empieza por `-` y da `+-`/`--`—: salió **diff vacío** sobre un fichero que sí había cambiado. En un -corpus que es casi todo viñetas, ese filtro **borra la mayoría de lo que buscas**.)* +el testigo de presencia **sale verde en los dos casos**. *(cicatriz `C-046`)* ⇒ **Un filtro que no casa no se queja: devuelve nada** — indistinguible de «no hay nada». Cuando un instrumento devuelva vacío, **pruébalo contra un caso que SÍ debería encontrar** antes de concluir. **② MENCIÓN en lugar de VALIDACIÓN.** Un esquema **no declara lo que deja de comprobar**: acepta el documento, devuelve verde, y el hueco no aparece en ninguna parte. ⇒ **Leer un esquema no te dice qué -valida: te dice qué MENCIONA.** *(Cuatro mutantes sobre el netplan real de un host. El -`autoinstall_schema` del controlador de red de subiquity pone `ethernets: {properties: {match: -MATCH}}` con `MATCH` llevando `additionalProperties: false`, y de ahí se afirmó que un `match` con -una clave de más sería rechazado. **Falso**: ese `match` cuelga **directamente de `ethernets`**, -profundidad donde netplan **no lo pone jamás**; el de verdad vive en `ethernets..match`, y ahí -el esquema **no mira**, porque `ethernets` no lleva `additionalProperties: false`.)* +valida: te dice qué MENCIONA.** *(cicatriz `C-047`)* ``` version: 3 -> RECHAZADO ("3 is greater than the maximum of 2") typo `macadress` en prov0.match -> PASA <- la afirmacion, refutada @@ -769,11 +580,7 @@ iba a proteger de una trampa puede estar cometiéndola.** **③ OTRO MECANISMO en lugar del que NOMBRA — y ésta es la que no caza ningún gate genérico.** La guarda enrojece de verdad, pero **por un camino distinto del que dice medir**, así que **quitar -aquello que anuncia comprobar NO la pone roja**. *(`proyectos-3c`, sobre el arranque por red: -predijo **1 rojo** en su mutante y salió **0**. Su comprobación decía medir *«el servidor que ignora -el `Range`»* y en realidad pasaba por **el magic `CD001` ausente en unos bytes de relleno**. La -arregló con un fichero que **parece correcto a la profundidad equivocada** — literalmente `A13` en -otro traje.)* +aquello que anuncia comprobar NO la pone roja**. *(cicatriz `C-048`)* ⇒ **Sólo la separa MUTAR LA GUARDA CONCRETA QUE NOMBRA.** Un mutante genérico no la distingue de una comprobación sana: hay que romper **el mecanismo que la cabecera dice medir**, y ver si enrojece. @@ -791,13 +598,7 @@ tranquilo, que es lo peligroso. **Un mutante irreal es un verde disfrazado de ri ⛔ **«TODAVÍA NO SE LE HA APLICADO X» NO ES «LE FALTA X».** Confundirlos convierte **el estado normal de cualquier sistema antes de su paso de configuración** en un incidente — y gasta la credibilidad que hará falta el día que haya uno de verdad. -*(Cicatriz 2026-09-02: **tres sesiones a la vez** leyeron *«el nodo conserva la ranura de recuperación -de LUKS»* como un agujero de seguridad, lo escalaron y llegó a la mesa de Xavier. Es la **definición -del estado previo**: esa ranura la retira el día 1, y a ese equipo el día 1 no se le ha aplicado. Lo -deshizo él en dos líneas: **«no se puede pretender que esté securizado antes de que se le aplique la -securización»**. Y el caso puro estaba delante: la máquina que la conservaba está **sin bastionar a -propósito**, porque es **la línea base contra la que enrojece la mitad roja de los gates** — pedirle -que no la tenga es pedirle que deje de servir para lo que existe.)* +*(cicatriz `C-049`)* ⇒ ⛔ **Pero el contrapeso va PEGADO, o este raíl se convierte en la excusa**: **aceptar que un estado intermedio es legítimo no elimina su DURACIÓN.** *«Aún no bastionado»* es correcto como **estado** y no lo es como **situación que dura tres semanas sin que nadie la mire** — y la diferencia no la marca @@ -810,19 +611,13 @@ separados se separan también en el tiempo**, y el hueco entre ellos no aparece mal **en varios sitios**, y arreglar el que tenías delante **produce la sensación de cerrado** sin serlo — con el agravante de que ahora el corpus **se contradice a sí mismo** y el lector cree al que abrió primero. -*(Cicatriz 2026-09-02: se corrigió la ficha que decía `.50 = ESXi / .51 = iLO` —al revés— y se dio por -cerrado. Quedaba un **tercer** fichero diciéndolo mal **dos veces más**, y la peor **no era una -descripción sino un PROCEDIMIENTO**: «asignar `.50` al VMKNIC y `.51` al iLO». ⇒ ⭐ **Un dato malo en -una descripción se LEE; en un procedimiento se EJECUTA.** Lo cazó una pregunta de otra sesión — -**«¿cuál corregiste?»**—, que es comprobar el **sujeto** de un arreglo, no su existencia.)* +*(cicatriz `C-050`)* ⇒ **Antes de dar por cerrada una corrección de dato: `grep` del dato en TODO el corpus, y control final que salga vacío.** Y al mirar los resultados, **los procedimientos primero**. ⛔ **UN ARNÉS CON UNA RUTA ABSOLUTA A UN SCRATCHPAD ES CÓDIGO QUE NO CORRE — y no da síntoma, porque nadie lo ejecuta hasta que hace falta**, que es el peor momento posible para descubrirlo. -*(Cicatriz 2026-09-02: el banco de subiquity del motor de `hermes-infra` estaba commiteado con rutas -absolutas al **scratchpad de OTRA sesión** —un directorio con el UUID de una conversación que ya no -existe— más un `/mnt/c/.../sp2` de relleno. **Tenía casa en el repo y no arrancaba.**)* +*(cicatriz `C-051`)* ⇒ ⭐ **Y la segunda mitad es la que engaña**: su propio aviso decía *«ya no vive en un scratchpad»* — **cierto del CÓDIGO y falso de sus RUTAS**. Se mudó el fichero y no lo que el fichero apunta, y el aviso habló de la mitad que se había hecho. Misma forma que la ambigüedad de sujeto: **la afirmación @@ -833,11 +628,7 @@ aviso de la mudanza, di **de qué mitad hablas**. ⛔ **UNA AUSENCIA NO ES UNA CAUSA HASTA QUE COMPRUEBAS QUE ANTES ESTABA.** Encontrar que *falta* algo —una ruta por defecto, una etiqueta, una clave— es el final de la búsqueda sólo si esa cosa **debía estar**; si nunca estuvo, reponerla no arregla: **cambia el sistema**. -*(Cicatriz 2026-09-02: al nodo IA le faltaba la ruta por defecto tras un corte. Se propuso reponerla -apuntando al **firewall nuestro**, que da salida a internet — y **la máquina es de otro equipo**, con -su gateway propia sin internet real. Lo paró Xavier diciendo **por qué** no la quería, y sólo -entonces se leyó el documento que lo explicaba. ⇒ ⭐ **La ausencia era real y la causa también, y aun -así el arreglo habría sido un cambio no autorizado en la máquina de un tercero.**)* +*(cicatriz `C-052`)* ## 2. El dato crudo, no el cocinado @@ -867,9 +658,7 @@ no sólo *cómo* se parsea. ⛔ **Cuando un cambio de configuración pretende cambiar un COMPORTAMIENTO, el testigo es el ARTEFACTO GENERADO: guardado ANTES, comparado DESPUÉS, y el veredicto es su `diff` por caso.** **Un caso cuyo diff sale vacío no está construido, aunque no dé error: es un campo-señuelo.** -*(Cicatriz del motor de aprovisionamiento, cosecha 2026-08-15: `day1.mode` — dos modos producían **el mismo -artefacto**; y así llegó `day0.luks` a existir declarado y sin consumir, sin que nada se pusiera -rojo.)* +*(cicatriz `C-053`)* ⇒ Es el testigo independiente de §1 aplicado a la configuración: sin el artefacto de antes, «cambié la perilla y no dio error» no distingue **construido** de **decorativo**. @@ -887,58 +676,27 @@ test, ahí no hay cobertura — hay una simulación de que la hay. El testigo ti donde entra el usuario**. ⛔ **El NÚMERO de rojos es la señal, no el rojo.** Una mutación que da **menos** rojos de los que -esperabas acusa a **tu test**, no a la mutación. *(Cicatriz F11.11b, 2026-07-27: el test de -cableado recorría `app.routes` **en plano**, pero en esa versión de FastAPI los routers incluidos -van **anidados** → el recorrido veía 8 rutas y **ninguna** `/api/…`, así que **pasaba con el -endpoint abierto de par en par**. Se delató porque la mutación dio **1 rojo donde tenían que ser -2**. Ahora las rutas se descubren por el esquema OpenAPI.)* +esperabas acusa a **tu test**, no a la mutación. *(cicatriz `C-054`)* ⇒ **Escribe cuántos rojos esperas ANTES de mutar.** Sin esa predicción, un rojo de menos pasa por éxito y el placebo sobrevive. -⇒ **Y para que el conteo SEA posible, las aserciones tienen que ser a prueba de `nil`.** *(F11.12, -2026-07-27: tal cual estaban, la primera mutación **reventaba el bloque entero** y escondía cuántas -aserciones habría tumbado — el número dejaba de ser medible justo cuando lo necesitabas.)* Una +⇒ **Y para que el conteo SEA posible, las aserciones tienen que ser a prueba de `nil`.** *(cicatriz `C-055`)* Una suite que explota en vez de suspender no te deja contar rojos. ⇒ **Y un 0 rojos puede significar «la mutación NO se aplicó».** Distínguelo, o una mutación que no -casó se lee como *«el test no cubre esto»* y sale a la basura una comprobación buena. *(2026-07-27: -una quinta mutación dio 0 donde se esperaban 2 — **el arnés avisó de que el `sed` no había casado**, -así que el cero quedó explicado en vez de pasar por bueno.)* El arnés de mutación tiene que +casó se lee como *«el test no cubre esto»* y sale a la basura una comprobación buena. *(cicatriz `C-056`)* El arnés de mutación tiene que **afirmar que el fichero cambió** antes de correr la suite. ⇒ ⭐ **Y una forma concreta de que no case, que no es un `sed` mal escrito: mutar donde el valor se -HEREDA en vez de donde se DECLARA.** *(2026-08-13: una mutación apuntaba a `values-hermes.yaml` para -tocar la clase de Ingress — y esa instancia **no la declara, la toma del default** ⇒ no había nada -que mutar. El arnés dijo «mutación no aplicada» en vez de un `0 rojos` que se habría leído como -«esto no está cubierto», y la mutación se reapuntó al default, donde sí enrojece las tres.)* ⇒ Antes +HEREDA en vez de donde se DECLARA.** *(cicatriz `C-057`)* ⇒ Antes de mutar un valor, pregunta **dónde está escrito de verdad** para la instancia que vas a medir. -⇒ **Y aun cambiando el fichero, el cero puede ser del CONTADOR.** *(2026-07-28, hub `I6`: la -mutación quitaba un `{% if %}` y dejaba su `{% endif %}` → la plantilla no compilaba, la suite moría -en el fixture y salían **31 `errors` y 0 `failed`**; el arnés leía solo `N failed` ⇒ **0 rojos**, -indistinguible de «este test no cubre nada», y por poco se tira una comprobación buena.)* Dos +⇒ **Y aun cambiando el fichero, el cero puede ser del CONTADOR.** *(cicatriz `C-058`)* Dos consecuencias: **cuenta los `errors`** —una suite que explota no es una suite que aprueba (es la misma familia que el `nil` de arriba, un piso más abajo)— y **muta a algo sintácticamente válido**: 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.** *(Misma sesión: la mutación puso `10.99.0.2` a -pelo… que era exactamente el valor contra el que afirmaba el test → **verde por coincidencia**, con -el número de rojos acertado y la identidad equivocada. Con `10.99.0.77` salieron 3.)* 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. ⛔ **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 2026-08-05, construyendo el gate de -`R14`, y lo cazó la mutación —no el gate en verde— que es la única razón por la que se sabe:* -- ***casar por SUBCADENA y no por LÍNEA***: `grep -q 'port: 444'` salía **verde contra - `port: 4440`**, o sea que la guarda del puerto decía que sí a un valor que no era. Es el - `head -1` de `A16` en otra sintaxis: *leer por posición o por trozo, nunca por identidad*. - ⇒ ⭐ **Y su forma PEOR, medida el 2026-08-13: cuando las dos cadenas son valores LEGÍTIMOS del - sistema, la subcadena engaña en las DOS direcciones.** `nginx-inet` **contiene** `nginx`, y las - dos son clases de Ingress reales de instancias distintas ⇒ una guarda sin ancla `$` decía - `ok [hermes] … emiten nginx` **sobre un render que ponía `nginx-inet`**. Aquí el falso positivo no - es ruido: es *el valor de otro hub*. ⇒ Ancla siempre, y si puedes **compara la cadena exacta en - vez de buscarla** — el `pytest` de esa misma sesión aguantó justo por eso. -- ***`cmd | grep -q` bajo `set -o pipefail`***: `grep -q` sale al primer acierto y cierra la - tubería ⇒ **SIGPIPE al productor** ⇒ la tubería devuelve distinto de cero ⇒ **rojos - intermitentes**. Y lo grave no fue el caso nuevo: estaba **latente en cinco comprobaciones - preexistentes cuyo «ok» es la rama `else`** — o sea que llevaban tiempo pudiendo aprobar por el - motivo equivocado.*)* +que no se ejecuta suele ser el que declara `ok`. *(cicatriz `C-060`)* ⇒ Dos preguntas antes de fiarte de una comprobación, y las dos se contestan leyéndola: **¿casa por línea o por subcadena?** y **¿cuál de mis dos ramas es el `ok`?** Si el `ok` es el `else`, cualquier error en la condición **pasa por éxito**. ⭐ Y el corolario que lo hace barato: **muta también el @@ -952,9 +710,7 @@ que no discrimina (§1), y aquí encima *da permiso a todo el gate*. completa no es *«¿cambió?»* sino **«¿está el texto nuevo, y ha desaparecido el viejo?»** — y para una mutación que debe ser única, **cuántas veces**. - ⛔ **Una función del arnés usada ANTES de definirse no falla: sale `command not found`, y eso no - para el script ni cuenta como `FAIL`.** *(Misma sesión: un helper `quiere_linea` definido 300 - líneas después de su primer uso ⇒ la cara **positiva** de esas comprobaciones no se ejecutaba y - **nadie se enteraba**.)* Es el *«¿cuál de mis dos ramas es el `ok`?»* un piso más abajo: aquí no se + para el script ni cuenta como `FAIL`.** *(cicatriz `C-061`)* Es el *«¿cuál de mis dos ramas es el `ok`?»* un piso más abajo: aquí no se ejecutaba **ninguna** de las dos. ⇒ Un banco en shell necesita **suelo de comprobaciones EJECUTADAS**, no solo de fallos: si esperas 40 y corren 33, el arnés está roto aunque salga verde. ⭐ **Y lo que lo cazó fue la predicción por NOMBRE**: el conteo dio **+7 donde se predijeron +8**. @@ -964,29 +720,15 @@ que no discrimina (§1), y aquí encima *da permiso a todo el gate*. ⛔ **Antes de leer un solo conteo, comprueba que la BASE está VERDE.** Un banco cuya línea base ya suspende **no mide nada**: los rojos rancios viajan dentro de cada mutación y —esto es lo que nadie espera— **una mutación puede TAPAR uno**, así que el número sube o baja por motivos que no tienen -que ver con lo que mutaste. *(Cicatriz `H19`, 2026-08-05: el banco de `pq-sync.sh` llevaba **ocho -días** con la base en `17 ok / 4 fallos`, porque `62707e1` retiró del chart la semilla PQ legacy -—tocó **cinco ficheros y no tocó el banco**— y cuatro casos quedaron afirmando sobre algo que ya no -existe. Con esa base, los «más rojos de los previstos» **no eran una cascada**: N2 hacía pasar un -rancio y N4 otro. Y el aviso que lo describía prescribía **re-derivar los conteos**, o sea maquillar -la avería — §6, *un pendiente rancio trae el arreglo equivocado*.)* +que ver con lo que mutaste. *(cicatriz `C-062`)* -⇒ ⛔ **Y predice por NOMBRE, no por número: un conteo es un hash con pérdida de la verdad.** *(Misma -cicatriz, y es la mitad que asusta: `N1` era la **única** mutación en verde del banco… y lo era -**por coincidencia**. Sus dos rojos eran dos rancios, y **las dos aserciones que esa mutación existe -para romper salían VERDES** — el aviso colado por stdout subía el conjunto de 1 a 2, justo lo que se -esperaba. El número acertaba y la identidad estaba entera equivocada: no eran 4 de 5 mal, eran -**5 de 5**.)* Escribe **qué aserción, por su nombre**, debe ponerse roja y por qué; el número sale de +⇒ ⛔ **Y predice por NOMBRE, no por número: un conteo es un hash con pérdida de la verdad.** *(cicatriz `C-063`)* Escribe **qué aserción, por su nombre**, debe ponerse roja y por qué; el número sale de esa lista, nunca al revés. ⇒ ⛔ **Y su generalización, que es la que hace daño: si en un fichero conviven DOS FAMILIAS de comprobación, el conteo global no es comparable con nada.** No es que el número mienta un poco: es que **suma peras y manzanas**, así que una predicción hecha sobre una familia se caree contra el -total y salga un abismo. *(Cicatriz 2026-08-06, y salió bien **porque la predicción iba por -nombre**: al coser seis comprobaciones de `guards.sh` se esperaban **6 `ok`** y salieron **37**. Los -31 de sobra eran `quiere_fallo` —otra familia: lee `stderr` y afirma en positivo—. Con la -predicción hecha solo con el número, la conclusión habría sido «me faltan 31» y se habrían -«arreglado» **31 comprobaciones sanas**.)* +total y salga un abismo. *(cicatriz `C-064`)* ⇒ Antes de comparar dos conteos, pregunta: **¿cuentan lo mismo?** Y si el fichero mezcla familias, el testigo no es el total — es **el subconjunto nombrado**. @@ -997,10 +739,7 @@ caduca.** ⇒ ⛔ **Y una base roja no solo falsea los conteos: ESCONDE MUTACIONES MUERTAS.** El banco se corta antes de llegar a mutar, así que una mutación que dejó de casar **nunca llega a quejarse** — no sale -como «0 rojos», no sale de ninguna forma. *(Cicatriz 2026-08-06, y apareció **al poner la base en -verde**, no antes: la mutación 4 de `pq-secret.sh` llevaba desde `R14` sin casar, porque `R14` movió -los volúmenes a `_helpers.tpl` y en `deployment.yaml` ya no queda ningún `items:`. Dos días de censo -no la vieron porque los dos rojos de la base la tapaban.)* ⇒ Arreglar la base no es el final del +como «0 rojos», no sale de ninguna forma. *(cicatriz `C-065`)* ⇒ Arreglar la base no es el final del trabajo: **es cuando empieza a haber datos**. ## 4. Ejercita el flujo real (abre el navegador, toca el device) @@ -1012,19 +751,12 @@ Tests verdes ≠ funciona. Conduce el flujo de punta a punta en el medio real. - El PSK PQ, el `.ipk`, el DNS: validados en el router de campo real, no en mock. ⛔ **Sondear una escritura ES escribir.** Un cuerpo malformado **no** es una sonda segura: una API -cuyos campos son todos opcionales lo acepta encantada como *«pon todo por defecto»*. *(Cicatriz -2026-07-26: comprobar si `PUT /api/config/global` pedía credencial con `{"__probe__":1}` **vació la -Global Config** del hub y disparó el `write_zones()` — el hub dejó de servir sus tres estáticos -durante ~45 s.)* Sondea con un método que **no pueda mutar** (`OPTIONS`, un id inexistente), o +cuyos campos son todos opcionales lo acepta encantada como *«pon todo por defecto»*. *(cicatriz `C-066`)* Sondea con un método que **no pueda mutar** (`OPTIONS`, un id inexistente), o contra una copia. Y si la lías, **restaura desde el `GET` de hace un segundo y cuéntalo**, que es lo que hizo esa sesión: 45 s, verificado, y la única huella un contador de versión. **Y por el MISMO CAMINO que el usuario.** Un verde obtenido por otra ruta no dice nada de lo que él -ve. *(Cicatriz F11.7, 2026-07-26: «Guardar cambios» no guardaba… y sí guardaba. `apply_default` -hacía `ifup lan` incondicional, y la br-lan **es la interfaz por la que se administra el panel** → -el `ifup` se llevaba el socket de **su propia respuesta**. El backend aplicaba y persistía, y se -quedaba sin poder contestar; en el navegador, `r.json()` reventaba y la promesa del handler moría -sin dueño. Silencio absoluto.)* +ve. *(cicatriz `C-067`)* - 🔑 **Instrumento de diagnóstico: la MISMA petición por DOS caminos.** Fue lo que lo destapó — por la **LAN** (la interfaz editada): `RESET` a 0,78 s; por la **WAN**: `201` en 3,5 s. Misma @@ -1060,18 +792,11 @@ cosa**. **Los tres casos en que se pregunta:** **①** ⛔ **Cuando la decisión contradice algo medido.** Ahí el porqué **suele ser la medida que -faltaba** — no un desacuerdo. *(Cicatriz 2026-09-01: se recomienda **no tocar** el quórum de -almacenamiento esa noche, con números. El usuario decide **tocar**, y da su razón: **«el sitio caído -no depende de mí, no tengo control sobre él»**. ⇒ Eso **desmontó la premisa de la recomendación** —que -trataba la vuelta del sitio como una **certeza**— y **cambió el modelo de riesgo, no la conclusión**. -Sin la razón se habría aplicado lo mismo **creyendo otra cosa**.)* +faltaba** — no un desacuerdo. *(cicatriz `C-068`)* **②** **Cuando la decisión va a la capa que otros leen** —el registro de decisiones, un entregable— **y la leerá alguien que no estuvo**: dentro de tres semanas, o un tercero que audita. **Un veredicto sin razón adquiere invariantes que nadie decidió.** -**③** **Cuando el porqué define el SUJETO.** *(Ejemplo del mismo día: se decide soltar un filtro de un -control, y la razón es «**puedo responder por mí, no por lo que hagan las demás personas**» ⇒ el sujeto -del control **no son las cuentas de hoy: son las que otro cree mañana**. Sin esa frase, el gesto es -correcto y **apunta a la cosa equivocada**.)* +**③** **Cuando el porqué define el SUJETO.** *(cicatriz `C-069`)* ⛔ **Y cuándo NO se pregunta**, que es la mitad que evita el interrogatorio: **preferencias**, **gestos rutinarios**, y **cuando la razón ya se ve en lo dicho**. Preguntar por todo **entrena a contestar por @@ -1084,12 +809,7 @@ Método salieron de un porqué suyo y no de un hallazgo técnico.* ⛔⛔ **UN CAMBIO PENSADO PARA RECUPERAR REDUNDANCIA PUEDE NECESITAR LA REDUNDANCIA QUE AÚN NO TIENES — Y ENTONCES EL GESTO SE BLOQUEA A SÍ MISMO.** *«Es literalmente una línea»* puede ser **cierto del destino y falso del trayecto**, y **el trayecto sólo se ve recorriéndolo**. -*(Cicatriz 2026-09-01: con el quórum de almacenamiento a 2 de 3, se relaja la regla que impide colocar -un tercer testigo. El orquestador, para aplicar la colocación nueva, intenta **parar uno de los dos -que quedan** — y el sistema se lo **deniega** con «no quedarían suficientes». Como actualiza los -existentes **antes** de crear el tercero, **la operación se impide a sí misma**: cuatro reintentos, el -failover parado. Se desatascó reiniciando el orquestador, que al arrancar limpio pudo actualizar -primero **el testigo caído** —que no dispara la guarda porque ya está parado—.)* +*(cicatriz `C-070`)* ⇒ ⭐ **Y la salvaguarda que lo denegaba NO estaba en el análisis de riesgo**: se había estimado que recrear un testigo era *«el comportamiento normal, probabilidad alta»* — y **había un guardia debajo que lo impide**. La estimación era **pesimista**, y **no se supo razonando: se supo ejercitándolo**. @@ -1098,12 +818,7 @@ recuperada**. Quien lo reponga **después** de que el sistema retire la pieza pr encontrará el mismo bucle**. ⇒ **Escríbelo junto a la reversión, o la reversión es una trampa.** ⛔ **Y LA PREMISA DE UNA RECOMENDACIÓN TAMBIÉN SE MIDE — INCLUIDA LA MITAD QUE NO ES TÉCNICA.** -*(Misma noche: la recomendación de **no tocar** se apoyaba en **«mañana se recompone solo»** — que -**presupone como CIERTO que el sitio caído vuelve mañana**. No lo era: **no dependía de quien decidía**, -no había acceso fuera de banda, y dependía de poder desplazarse. Se puso en la balanza un riesgo -improbable contra **algo tratado como certeza sin haberlo comprobado**: la comparación estaba viciada -de origen. Y el otro platillo decía *«de noche y al final de un día largo»* — **cuando el usuario -estaba despierto y delante**.)* +*(cicatriz `C-071`)* ⇒ ⭐ **Un factor humano que se ASUME en vez de preguntarse es un dato inventado**, y pesa igual que uno técnico. ⇒ Antes de recomendar esperar: **¿de quién depende que mañana se pueda?** Si la respuesta no es *«de nosotros»*, **esperar no es la opción conservadora: es la que delega el resultado en algo @@ -1113,10 +828,7 @@ algo puede fallar, falla».)* ⛔⛔ **UN `latest` NO ES UNA VERSIÓN: ES UNA BOMBA CON TEMPORIZADOR DE REINICIO.** No falla cuando alguien mueve el tag — **falla la próxima vez que el proceso arranque**, que puede ser **meses después y por una causa ajena al sistema**. -*(Cicatriz 2026-09-01: un electricista mete un pico de tensión, salta un diferencial y reinicia **un** -servidor. Un motor de base de datos que llevaba **173 días** corriendo su versión vieja **en memoria** -tira la imagen nueva al rearrancar y muere: los datos en disco eran de la **9.6**, la imagen de hoy la -**26.7**. **El defecto se plantó el día que se movió el tag; el corte sólo lo reveló.**)* +*(cicatriz `C-072`)* ⇒ ⭐ **Y el corolario, que invierte la intuición: CUANTO MÁS ESTABLE ES EL PROCESO, MÁS GRANDE ES LA DIVERGENCIA ACUMULADA.** 173 días separaron una versión de otra. **La estabilidad no reduce el riesgo: lo carga.** Un servicio que lleva medio año sin reiniciarse **no es el más seguro: es el que más lejos @@ -1134,21 +846,14 @@ arreglo**: la explosión te dice que hay un campo de minas, no que hubiera una. ⛔⛔ **UN ÁRBITRO QUE DEPENDE FÍSICAMENTE DE UNO DE LOS DOS LADOS NO ES UN ÁRBITRO.** Un diseño de tolerancia por sitios —dos y dos, más un tercero que decide— **puede ser correcto en la capa que lo declara y no sostenerse, porque LA RED NO ACOMPAÑA AL DISEÑO.** -*(Cicatriz 2026-09-01: un cluster con `2+2+árbitro`, el árbitro en un **tercer** emplazamiento con -switch propio ⇒ sobre el papel, impecable. Medido por el `Designated Bridge` del root port: **ese -tercer sitio cuelga físicamente del switch del sitio A**, y su enlace redundante lleva **los dos -puertos caídos y sin transceptor** —diseñado y **nunca completado**—. ⇒ Apagar el sitio A **no se -lleva 2 nodos: se lleva 3**, y el quórum pasa de `3 de 5` a **`2 de 5`: se pierde**, en el plano de -control **y** en el almacenamiento. **No se degrada: se para.**)* +*(cicatriz `C-073`)* ⇒ **La comprobación no está en la capa que declara la tolerancia**: `etcd` dice cuántos miembros hay y dónde, **no por dónde llegan**. ⭐ **Pregunta a hacerse siempre: ¿por qué CAMINO físico llega el que decide?** Si la respuesta pasa por uno de los lados que arbitra, **el diseño es correcto y la propiedad no existe**. ⛔ **Y EL COROLARIO, QUE ES LO QUE MÁS ENGAÑA: EL PRECEDENTE QUE DA CONFIANZA PUEDE SER JUSTAMENTE EL -QUE NO CUBRE TU DIRECCIÓN.** *(La misma operación se había hecho **una semana antes** y salió bien — -pero sobre el **lado contrario**, que era del que **no** colgaba el árbitro. **La asimetría era -invisible desde el éxito.**)* +QUE NO CUBRE TU DIRECCIÓN.** *(cicatriz `C-074`)* ⇒ **Un precedente prueba la dirección que recorrió, no la operación.** Antes de apoyarte en él: **¿qué es DISTINTO entre aquella vez y ésta?** — y si la respuesta es *«nada relevante»*, **eso hay que medirlo, no suponerlo**: en ese mismo caso, **la carga estaba 169 contra 89** porque la ventana @@ -1161,20 +866,13 @@ por los dos lados, en dos frentes distintos. **(a) Un hallazgo que invalida una decisión va a quien la LLEVA, no sólo a quien la ejecuta.** Contestar a quien pregunta **no es reportar**. Son dos destinatarios y dos contenidos: el ejecutor recibe **qué hacer ahora**; quien decidió recibe **que su decisión ya no se sostiene**. -*(Cicatriz 2026-08-30: una sesión de ejecución pregunta si puede quitar un campo de una plantilla -para implantar una decisión. La medida dice que **ese campo es obligatorio en el instalador ⇒ -quitarlo rompe TODAS las instalaciones**, en la validación, antes de tocar el disco. Se le contesta -**a ella y sólo a ella** — pero eso **invalida media decisión**, y la decisión la llevaba su -orquestadora, que **siguió planificando horas sobre una premisa ya sabida falsa**. Salió porque el -usuario preguntó «¿esto se lo reportaste a la orquestadora?».)* +*(cicatriz `C-075`)* ⇒ Y por eso **un fallo de MÉTODO se le dice a la superadmin** *(Xavier, el mismo día: «cada cosa a su ámbito»)*: quien lleva el método es el destinatario, igual que quien lleva la decisión. **(b) Cuando otro frente te reporta algo y lo arreglas, EL ACUSE ES PARTE DEL ARREGLO.** Un arreglo silencioso **no es más barato: es más caro**, porque el otro frente **sigue gastando en -vigilar algo ya hecho**. *(Cicatriz del mismo día: un frente reporta que una plantilla de ejemplo -enseñaba una capa contra una decisión del usuario, y cede el sujeto. Se arregla y se empuja… y no se -avisa. El que lo reportó se queda con su aviso abierto, persiguiendo lo que ya estaba resuelto.)* +vigilar algo ya hecho**. *(cicatriz `C-076`)* ⇒ La entrega termina en **el que reportó**, no en el `push`. @@ -1182,10 +880,7 @@ avisa. El que lo reportó se queda con su aviso abierto, persiguiendo lo que ya en que el estado cambió y quien informa no estaba delante**: entre que avisaste y llega el sucesor, alguien pudo arreglarlo. Reenviar el aviso viejo **manda a la nueva a perseguir algo ya hecho** —y peor, **con la autoridad de venir de quien lo descubrió**. -*(Cicatriz 2026-08-30, **dos veces el mismo día y en direcciones opuestas**: un frente avisa al relevo -de que cierta decisión seguía apoyada en una premisa falsa… **y ya estaba corregida y sustituida**, -por él mismo, la víspera. Y la superadmin repite ese mismo aviso al día siguiente **sin volver a -mirar**. Las dos veces lo cazó la sesión nueva, que era la única que **no daba el estado por sabido**.)* +*(cicatriz `C-077`)* ⇒ ⭐ **Y las tres de este bloque son la misma familia con el fallo movido de sitio**: **(a)** falla **a quién** · **(b)** falla **que no se dijo** · **(c)** falla **cuándo**. En las tres **el dato es correcto** — lo que está mal es **a quién, o desde cuándo, se refiere**. @@ -1196,11 +891,7 @@ correcto** — lo que está mal es **a quién, o desde cuándo, se refiere**. ⛔ **UN ARTEFACTO QUE DEBE REFLEJAR EL TRABAJO Y NO ESTÁ EN EL RITUAL DE CIERRE DEJA DE CRECER AL RITMO DEL TRABAJO — EN SILENCIO.** No se rompe, no avisa: simplemente **se queda en la fecha del último día en que alguien se acordó**. -*(Medido 2026-08-31: en un frente que entrega a un tercero, el entregable tenía medidas de las -familias construidas **hasta el 27-ago y ninguna posterior**. **No eran diez olvidos**: una familia se -daba por cerrada cuando el rol la aplicaba y el auditor la veía verde, y **el entregable no estaba en -ese ciclo** ⇒ cada familia nueva abría un hueco nuevo. Y en el mismo día, otro frente: la mitad de una -tarea **construida** y **su backlog sin saberlo**.)* +*(cicatriz `C-078`)* ⇒ **El gesto que lo cierra es nominal y decidible**: algo **no está cerrado hasta que declara qué ha producido aguas abajo**, y **lo declarado se cuenta e imprime**. Una unidad cerrada que **no declara nada, enrojece**. @@ -1213,10 +904,7 @@ no que sea cierta, **y se dice**. SE RESOLVIERON.** Escribir un problema **está motivado** —duele, molesta, bloquea—; escribir que se arregló **no lo está**, porque el dolor ya paró. ⇒ **Lo que se queda rancio no es lo que empeoró: es lo que MEJORÓ.** -*(Medido el mismo día, en tres frentes y en el propio gobierno del árbol: un aviso decía que un banco -vivía en un scratchpad **del que ya había salido**; un pendiente declaraba certificados RSA que -**llevaban dos días siendo ECDSA**; y cuatro premisas del corpus raíz quedaron falsas **el día que el -árbol pasó a ser un repo git** — las cuatro por una mejora, ninguna por un fallo.)* +*(cicatriz `C-079`)* ⛔ **Y en un entregable eso es peor de lo que suena: un pendiente rancio es una DEBILIDAD DECLARADA QUE NO EXISTE**, e invita a quien lo lea a hurgar en algo ya resuelto. ⇒ **Al cerrar algo, la pregunta no es sólo «¿lo apunto?», es «¿qué documento afirma hoy un problema que acabo de quitar?»** @@ -1225,8 +913,7 @@ que el Método no prevé —nacen de **lo que ese frente entrega**, y eso no se si no están declarados en ningún sitio, **quien mire ese corpus mañana no puede saber si es «tiene un incremento aprobado» o «se fue por su cuenta»**. ⇒ Es el raíl de fuente única **sin su otra mitad**: hay fuente, y **no hay lista de excepciones a la -fuente**. *(Y no es teórico: el propio linter mide **la copia sellada**, no lo que cada repo tiene de -más ⇒ **hoy un incremento es indistinguible de una deriva para el instrumento del árbol**.)* +fuente**. *(cicatriz `C-080`)* ⇒ **Se declara en `.metodo/INCREMENTO`** —del repo, no viaja—, una línea por documento con **ruta, fecha y por qué ESTE repo lo necesita**. Misma forma que las excepciones de commits, que ya está probada: **nominal, fechada, motivada, contada e impresa en cada corrida**. @@ -1238,11 +925,7 @@ y un gate que la adivinara daría **rojos crónicos**. Queda como criterio human LLEVA EL MÉTODO.** ⇒ **El frente es el único que puede VER la necesidad**: un documento extra nace de a quién entrega ese proyecto, y desde fuera no se deduce. -⛔ **Pero el frente NO puede decidir dónde vive lo que escribe.** *(Cicatriz 2026-08-31: una -orquestadora escribió **cuatro** raíles en su propio corpus creyéndolos suyos; **tres eran generales y -uno no**, y **ella no podía distinguirlos** — sólo ve su frente. Además, de los tres, uno se paró por -un motivo que ella no habría dado: **una ocurrencia no hace un raíl**. Y quien la paró **no fue un -gate: fue el usuario**.)* +⛔ **Pero el frente NO puede decidir dónde vive lo que escribe.** *(cicatriz `C-081`)* ⇒ Por eso el reparto es: **el frente dice QUÉ necesita y POR QUÉ, con la medida delante; quien lleva el Método decide SI es incremento o es Método, y QUÉ FORMA tiene.** Así **proponer desde el frente no tiene coste**: lo peor que puede pasar es que le digan que no. @@ -1251,12 +934,7 @@ tiene coste**: lo peor que puede pasar es que le digan que no. correcto, está escrito, y quien decide no puede verlo.** Evidencias, scripts de banco, mensajes de commit, comentarios dentro de un rol: **todos son sitios donde el trabajo cae de forma natural** y **ninguno se lee para decidir**. -*(Medido 2026-08-31: **tres instancias en una sola jornada**, en el mismo frente y todas ciertas —un -sujeto de prueba documentado en un directorio de evidencias y un script de banco · una deuda escrita -en el mensaje de un commit · una versión de herramienta medida cinco días antes, en un aviso, un -comentario del rol y la cabecera de una comprobación—. **Las tres las destapó otra sesión leyendo por -casualidad. Ninguna la cazó un gate.** Y en las tres, quien decidía llegó a proponer trabajo ya hecho -o a operar con un riesgo que no existía.)* +*(cicatriz `C-082`)* ⇒ **No es descuido de nadie**: las cuatro capas están pensadas **para el que ejecuta**. Falta el gesto que las cruza. ⇒ **Al medir algo que cambia lo que otro decidiría, la pregunta no es «¿lo he escrito?» sino «¿lo va a VER quien decide?»** — y el sitio donde cae solo casi nunca es ése. @@ -1265,10 +943,7 @@ nunca entró en ninguna capa»**. Son dos enfermedades y la fecha sólo ve una. ⛔ **UN INSTRUMENTO QUE NO PUEDE VER EL ESTADO MALO DEVUELVE LO MISMO EN LOS DOS ESTADOS — Y CONTESTA CON APLOMO.** No se equivoca: **no puede distinguir**, y su salida no lo dice. -*(Cicatriz 2026-08-31: `clevis luks list` **no puede desmentir** la existencia de una ranura de -contraseña — devuelve `1: tpm2` **con una ranura y con dos**. Se comprobaba justamente si esa frase -seguía abriendo el disco. La respuesta la dio otro instrumento, `luksDump`, que **sí enumera todas -las ranuras**.)* +*(cicatriz `C-083`)* ⇒ Es la cara consultiva de *«un gate que no puede enrojecer»*: allí el veredicto no puede ser malo; aquí **la pregunta no puede tener la respuesta que buscas**. ⇒ **Antes de creer una respuesta tranquilizadora, pregúntate si ese comando PODRÍA haber dicho lo contrario** — y si no, cambia de @@ -1280,11 +955,7 @@ que un home puede llevar una fecha meses anterior a la máquina)*. ⛔ Y la zanj ⛔ **UN DOCUMENTO PUEDE ACERTAR EL EFECTO Y EQUIVOCARSE DE COMPONENTE — y entonces manda a quien lo lea a depurar el sitio equivocado.** El síntoma correcto, la causa correcta y el arreglo correcto no salvan a un texto que nombra mal **de quién es el fallo**. -*(Cicatriz 2026-08-25→31: un aviso decía «el instalador no baja el seed» y nombraba a **subiquity**. -Quien pide las cuatro rutas y **valida la cadena TLS** es **`cloud-init`**; subiquity **consume** lo -que cloud-init ya le entregó. El aviso era **útil y accionable durante seis días** —el síntoma que -describía es el que se ve— y aun así habría mandado a depurar el componente equivocado. Lo escribió -un frente, **lo heredó otro al citarlo**, y lo corrigió el segundo al medirlo.)* +*(cicatriz `C-084`)* ⇒ Es la familia de **el instrumento que no dice de qué habla**, con una arista nueva: aquí **el documento no dice de QUIÉN**. Y muerde el doble cuando el texto acaba alimentando **una guía externa**, donde la diferencia entre *«lo vimos fallar»* y *«falla este componente»* es la @@ -1320,12 +991,7 @@ va al resumen como pregunta, no al código como hecho. ⛔ **La corrección va DONDE ESTABA EL ERROR, no debajo — y un documento «ya corregido» con el artefacto viejo intacto es PEOR que uno sin corregir**, porque la enmienda hace creer que está -resuelto. *(Cicatriz 2026-08-03, y es `A1` en versión nueva: `dns-malla.md` corrigió el 2026-08-01 su -modelo de resolución en un bloque «⛔ CORREGIDO»… y **dejó vivo el diagrama de arriba**, que dibujaba -la cadena vieja. Nadie lee el párrafo de enmienda: se lee **el diagrama**. Dos días después ese -diagrama era lo que Xavier tenía en la cabeza al describir el diseño, lo que la orquestadora escribió -como **premisa autoritativa** de un encargo, y lo que obligó a la sesión receptora a **parar**. El -modelo derogado sobrevivió a su propia derogación y volvió a entrar por la puerta grande.)* +resuelto. *(cicatriz `C-085`)* ⇒ Regla: **enmendar es SUSTITUIR.** Si lo que estaba mal era un diagrama, se corrige el diagrama; si era una tabla, la tabla. Un párrafo debajo que dice *«esto de arriba ya no vale»* deja el error en el sitio donde la gente mira, y encima le pone un sello de revisado. @@ -1341,11 +1007,7 @@ cosmético ni solo un remedio contra el tamaño: un bloque **`D` numerado, con d (usuario / técnica) y separado del texto normal** se distingue a un golpe de vista, y eso vale **también en un documento corto**. -⭐ **Un fallo de RED transitorio se lee como un fallo de PERMISOS si no reintentas.** *(Cicatriz -2026-07-27: dos sesiones concluyeron «esta máquina no tiene credenciales para `git.manabo.org`» y -dejaron un chart de producción sin aterrizar. Era falso — cinco pushes ese mismo día desde ese mismo -PC. El mismo día, un push a `git.c2et.com` falló con `Recv failure: Connection was reset` y **entró -al segundo intento**.)* Antes de convertir un fallo en una conclusión: **reintenta**, y si vuelve a +⭐ **Un fallo de RED transitorio se lee como un fallo de PERMISOS si no reintentas.** *(cicatriz `C-086`)* Antes de convertir un fallo en una conclusión: **reintenta**, y si vuelve a fallar, reporta el error **literal** en vez de tu interpretación de él — «connection reset» y «no autorizado» no son lo mismo y llevan a sitios opuestos. @@ -1362,27 +1024,15 @@ falsas** es el termómetro de *«estoy escribiendo de memoria»*. **«El doc lo verificar**, no una fuente. ⇒ ⛔ **Y hacia atrás, que es la mitad que se olvida: al ESCRIBIR un hallazgo se nombra la RUTA EXACTA que se midió, nunca la categoría.** Una categoría con **una sola medición** detrás se lee -después como universal, y de ahí se hereda como premisa falsa. *(Cicatriz cosecha 2026-08-15: «el -camino Rocky» eran **dos** caminos y solo se había medido uno; la frase viajó por tres documentos -antes de que alguien la careara.)* +después como universal, y de ahí se hereda como premisa falsa. *(cicatriz `C-087`)* ⛔ **Y una forma de romper un documento que no deja rastro: la CIRUGÍA POR NÚMERO DE LÍNEA.** Un `sed '1342,1453d'` o un `sed "${L}r fichero"` acierta o destroza según un número que **cambia con cada edición anterior de la misma sesión** — y el daño es *texto que desaparece*, que es justo lo que -no se nota releyendo por encima. *(Cicatriz 2026-08-18: la orquestadora editó así la ficha `I11` -durante toda una sesión y la rompió **dos veces** — un borrado se llevó la línea ⛔ *«que nadie -construya un des-aplicar»* (**el raíl que su propio encargo repetía**) y una inserción metió `I11.9` -**dentro de la viñeta de `I11.8`**, cuya cola quedó leyéndose como suya. Lo cazó la sesión siguiente -al ir a trabajar sobre la ficha; la orquestadora había «verificado» cada edición con un `grep` del -marcador nuevo, que **siempre casa** aunque el resto haya quedado hecho trizas.)* +no se nota releyendo por encima. *(cicatriz `C-088`)* ⇒ **Un `grep` del marcador que acabas de insertar no verifica una edición: verifica tu inserción.** ⛔⛔ **Y ESTE RAÍL ESTABA ESCRITO Y NO IMPIDIÓ NADA: SE CUMPLIÓ CINCO VECES SOBRE ESTE MISMO -DOCUMENTO.** *(Censo 2026-09-02: **cinco párrafos partidos en la matriz**. El más viejo llevaba -**tres días** repartido a los **27 repos** —lo partió, con ironía perfecta, el commit que añadía -«**la puerta hay que escribirla de modo que ATE, no que informe**»—; **dos eran de esa misma tarde y -de quien escribe esto**; y uno estaba **en la cabecera del documento**, la primera frase que lee toda -sesión. **Nadie vio ninguno**, porque una cola varada **se lee como el principio de otro párrafo**: -el texto no se rompe, se **recompone mal** y sigue siendo texto.)* +DOCUMENTO.** *(cicatriz `C-089`)* ⇒ ⭐ **La lección no es sobre `sed`: es que un raíl que depende de acordarse ES PROCEDIMIENTO, NO PROPIEDAD** — y este llevaba dos semanas escrito, en un documento que sus infractores tenían abierto. ⇒ ⭐ **Por eso se ató: `C39` del linter** compara cada línea que **acaba a mitad de frase** con la @@ -1404,15 +1054,7 @@ Un artefacto compartido vive en **un** sitio; los consumidores llevan copia **co componente = el contrato estaba bien puesto. ⛔ **Y cuando coses una cicatriz, BUSCA A LOS HERMANOS: un arreglo que no se propaga deja al gemelo -armado, y encima con la prueba de que el fallo es real.** *(Cicatriz 2026-08-06, censo de los bancos -del chart del hub: `aip-sync.sh` y `lo-reconcile.sh` son **dos drivers del mismo directorio que hacen -lo mismo** —extraer un bloque del render, mandarlo a un host y ejecutarlo como root—. El 2026-08-02 -`aip-sync.sh` se comió una extracción rota y se cosió bien: `awk`, anclas **afirmadas** y una -aserción negativa. A su hermano no lo miró nadie. Cuatro días después, en `mode: loadBalancer` el -ancla de cierre de `lo-reconcile.sh` **ya no existe** —`R14` quitó el reconciliador a propósito— -pero la de apertura sí, así que el rango del `sed` corre hasta el final del render: **893 líneas -donde son 36**, con los `ExternalSecret` dentro. Su única guarda es `[ -s ]`, que 893 líneas pasan -de sobra, y lo siguiente de ese script es `scp` + **`sudo bash`**.)* +armado, y encima con la prueba de que el fallo es real.** *(cicatriz `C-090`)* ⇒ La pregunta, y es la misma de la poda (§1): **¿quién MÁS hace esto?** Un arreglo se termina cuando se ha buscado al resto de sitios con esa forma — no cuando el fichero que fallaba pasa. ⇒ Y el sub-raíl que lo hace concreto: **una guarda de «no vino vacío» no protege de «vino de más»**. @@ -1422,19 +1064,13 @@ Si de lo extraído depende un `bash`, la guarda tiene que **afirmar las dos ancl **Si tocas artefactos del OTRO repo, le debes a ese repo su entrada — en la MISMA sesión.** El espejo cross-repo no se pudre por deriva de redacción: se pudre **asimétricamente**, porque el trabajo hecho desde el repo A sobre cosas de B se documenta solo en A. Síntoma: casillas `[ ]` en B -para cosas **desplegadas** en B. *(Cicatriz Hermes 2026-07-26: el sidecar Rosenpass corriendo en el -chart del hub y el backlog del hub dándolo por pendiente, con un plan que nunca ocurrió; y un fix -del hub —`F13.0-c`— que solo existía en el backlog del edge.)* La disciplina del espejo falló justo +para cosas **desplegadas** en B. *(cicatriz `C-091`)* La disciplina del espejo falló justo para el trabajo cross-repo, que es **para lo que existe el espejo**. ⛔ **PROPONER UN CAMBIO SOBRE EL MECANISMO DE OTRO FRENTE ES TOCARLO.** La regla de leer su contrato antes de meter mano **no aplica sólo a editar: aplica a SUGERIR** — porque **una propuesta técnica concreta de una orquestadora a otra tiene fuerza de encargo**, y se implementa. -*(Cicatriz 2026-08-30: un frente reporta a otro un testigo falso —correcto, aceptado— y **añade una -solución**: que cierto endpoint publique la fecha además del identificador. La dueña lo mide: el -endpoint devuelve el identificador **pelado**, la comparación del agente es **de cadena completa**, y -una línea de más hace que **no vuelva a coincidir nunca** ⇒ cada nodo **se re-descarga su árbol en -cada disparo, para siempre**.)* +*(cicatriz `C-092`)* ⛔⛔ **Y lo que lo hace grave es que NO HABRÍA FALLADO**: convergería igual, nadie lo notaría, y sólo gastaría de más **indefinidamente**. ⇒ Es **un cambio de contrato disfrazado de mejora del log**, y esa frase nombra la clase entera: los cambios que **no rompen nada** son los que **nadie revisa**. @@ -1450,10 +1086,7 @@ criterio de nadie**: fue **la frontera**, que obligó a mandar la propuesta en v aun así no pasa nada.** Mientras todos acierten, no sabes si tienes una frontera o una costumbre. ⛔ **Y el caso más caro de fuente doble no es un artefacto compartido: es el RELATO escrito DOS -VECES, en el backlog y en la bitácora.** *(Cicatriz 2026-08-18: la orquestadora documentó cada -hallazgo de dos días en los dos sitios; la ficha `I11` llegó a **464 líneas** y Xavier dijo que -**había dejado de poder leer el backlog**. La bitácora ya lo tenía todo: lo del backlog era una -copia pura.)* +VECES, en el backlog y en la bitácora.** *(cicatriz `C-093`)* ⇒ La regla que lo evita **ya existía** —*«las decisiones se quedan, la EVIDENCIA se va»*, `sesion-ordenacion-docs.md` (capa `workflows/`)— pero vivía **en el workflow de la sesión que LIMPIA, no en el de las que ESCRIBEN**, así que se incumplía sistemáticamente y se pagaba @@ -1461,11 +1094,7 @@ después en una pasada. Por eso está aquí ahora. ⛔ **COMPROBAR QUE ALGO ESTÁ NO ES COMPROBAR QUE HACE AQUELLO PARA LO QUE EXISTE.** Y la trampa es que **el artefacto puede ser correcto**: verificarlo sale **VERDE** y aun así el aviso sigue abierto. -*(Cicatriz 2026-08-31: un aviso pedía que el testigo de sincronía apareciera **donde mira quien -depura**. La línea se construyó, es correcta, nombra los dos identificadores y no miente… pero la -escribe un script que va a **un fichero de log distinto** del que recibe el resumen de la ejecución. -⇒ **El testigo existe y no viaja pegado a lo que se lee** — o sea, el gesto que el aviso existía para -quitar **sigue ahí**. Y lo destapó **una sola pregunta**: «¿dónde queda lo que imprime?».)* +*(cicatriz `C-094`)* ⇒ **La pregunta que lo caza no es «¿está?», es «¿QUIÉN LO VA A VER, Y CUÁNDO?»** — un piso por encima de comprobar la fuente: ahí la fuente declaraba y el artefacto no reconciliaba; **aquí el artefacto es correcto y está en el sitio equivocado**. @@ -1473,10 +1102,7 @@ correcto y está en el sitio equivocado**. ⛔⛔ **Y UN MENSAJE DE COMMIT NO ES UNA CAPA DEL CORPUS.** Lo dicho **sólo ahí** es, a efectos de quien decide, **invisible**: quien lee `AVISOS.md` —que es lo que se manda leer primero— lee **«RESUELTO»**. -*(Mismo caso: la sesión que construyó **ya había medido** que el testigo caía en otro log **y lo dejó -escrito, honesta y explícitamente… en el mensaje del commit**. Una deuda **medida, dicha y aun así -invisible desde el sitio donde se decide**. La encontró su relevo **por casualidad**, mirando el -`git log` para copiar la convención de mensajes.)* +*(cicatriz `C-095`)* ⇒ **Un mensaje de commit es el testigo de un CAMBIO, no el estado de un FRENTE.** Si lo que sabes cambia el estado, va a su capa **además** —`AVISOS.md`, `decisiones.md`, `backlog.md` o la bitácora— y el commit **puede** repetirlo. ⛔ **Nunca sólo en el commit**: es la quinta capa que nadie lee y que @@ -1501,11 +1127,7 @@ enteramos —lo medido, las predicciones, los mutantes, las premisas falsas, el **no es prudencia: es crear la deriva** que §7 existe para impedir, porque el día que uno de los dos se corrija el otro seguirá ahí. ⛔ **Y la cuarta capa existe porque una decisión guardada en el backlog se numera POR FASE, y la -numeración por fase colisiona.** *(Cicatriz 2026-08-22, `D6` de Xavier: **18 decisiones distintas -llamadas `D1`** en un solo `backlog.md` — y cuatro fallos de una semana que salen de ahí: un -**resumen** que gobernó en lugar de la decisión, un «precio aceptado» que Xavier nunca pensó, dos -ids que colisionaban, y una sustitución con las **dos versiones vivas** a 90 líneas de distancia. -En sus palabras, para qué sirve la capa: «así tienes todo lo peligroso en un único documento».)* +numeración por fase colisiona.** *(cicatriz `C-096`)* ⇒ Por eso se ordena **por ámbito, no por fase**; cada entrada lleva **texto íntegro** (nunca un resumen — un resumen adquiere invariantes que la decisión no tiene), **dueño visible** (*Xavier* o *técnica*: una técnica escalada como suya ya coló), **estado**, y el **testigo en la misma línea** @@ -1523,12 +1145,7 @@ es la que se sigue editando. La deriva no necesita descuido: necesita **una edic no se escriben en el borrador — **se aplican al máster**. Y si el autor no puede escribir en el máster (no es su ámbito), **los redacta y los entrega**; lo que no hace es guardarlos en su copia «hasta que se puedan aplicar», porque eso **es** la fuente doble, sólo que con buena intención. -*(Tres ocurrencias en cuatro días, la misma forma y sitios distintos: un `workflows/metodo.md` que -llevaba **6 días** siendo máster de facto porque el repartidor no alcanzaba ese árbol y nadie era su -dueño; una entrada de buzón escrita **explícitamente** como copia de seguridad *«que se retira -cuando su dueña la coloque»* —y que sólo se retiró porque lo llevaba escrito dentro—; y un borrador -de propuesta que **su propia autora vio convertirse en derivada** en el momento de aprobarse la -entrega, con dos cambios pendientes en la mano. Las tres se vieron; la primera, seis días tarde.)* +*(cicatriz `C-097`)* ⇒ ⭐ Y el testigo de que esto está bien resuelto **no es que el borrador esté al día: es que NO EXISTE**. Un borrador vivo junto a su máster es una fuente doble aunque hoy coincidan byte a byte — lo que se mide es **quién puede escribir en él**, no si ahora mismo difiere. @@ -1548,10 +1165,7 @@ hay ningún gate detrás que lo desmienta. ⛔ **Y LAS CUATRO CAPAS NO SE LEEN IGUAL: hay capas de ARRANQUE y capas de CONSULTA.** El corpus no crece porque se escriba de más —crece **porque funciona**— pero **se lee entero cada vez, y eso sí es -un defecto**. *(Medido 2026-08-29: arrancar una sesión de un frente maduro cuesta **1,40 MB ≈ 400 k -tokens** antes de hacer nada —`CLAUDE.md` raíz + la constitución + su corpus—, o sea **media ventana -de contexto gastada en leer**. Y ahí está la causa de que las sesiones se agoten y haya que -relevarlas: **el coste de arranque se paga en la moneda con la que se trabaja**.)* +un defecto**. *(cicatriz `C-098`)* ⇒ **El reparto, y sale de una medida, no de una intuición**: - **ARRANQUE** — `AVISOS.md` **primero**, luego `decisiones.md` y `backlog.md`, más el `CLAUDE.md` del repo. Es lo que dice **qué muerde hoy**. @@ -1568,10 +1182,7 @@ el relato de cómo se llegó — **todo eso tiene su capa, y no es ésta**. el estado interno»*, la regla se lee al **arrancar** y se incumple al **editar**, que es cuando haría falta. Igual que *«las decisiones se quedan, la evidencia se va»* vivía en el workflow de la sesión que LIMPIA y no en el de las que ESCRIBEN. -*(Cicatriz 2026-08-30: una sesión metió tres fechas, un `mtime` y **una cita literal del usuario** -dentro de un anexo firmado — **conociendo el principio**, que se lo habían dicho horas antes. Y el -usuario, al verlo: **«me paso el día matando historiales»** ⇒ no es un desliz de una sesión, es la -norma del sitio.)* +*(cicatriz `C-099`)* ⇒ Por eso la línea va **en la cabecera del propio entregable**, donde se edita, y no sólo aquí: un raíl que sólo vive en la constitución **llega tarde al gesto que lo rompe**. ⭐ **El testigo de que el reparto es correcto, y es una medida real**: una sesión limpia reconstruyó @@ -1587,25 +1198,20 @@ mañana**. *«Un sucesor no se atasca en una decisión de diseño; se atasca en ⛔ **Un AVISO es una BANDERA: si no cabe en una pantalla, no es una bandera — es un documento disfrazado.** La primera línea lleva **qué muerde y a quién**; el detalle va debajo, y el relato a la -bitácora. *(Cicatriz 2026-08-29: el `AVISOS.md` de un frente activo tenía **1.905 caracteres de -media por línea** y una de **8.196** — y es **el fichero que se lee primero**.)* +bitácora. *(cicatriz `C-100`)* ⇒ Y no es sólo volumen: **el título en negrita de un aviso es la superficie que acumula encuadres caídos**, porque se escribe para que muerda, porque un listado compacto **es lo único que enseña**, y porque corregir el cuerpo **se siente** como haber corregido el aviso. Un aviso ya llegó a tener el título equivocado **dos veces el mismo día**, con el cuerpo corregido las dos. ⇒ **Ante un encuadre caído, el título se censa PRIMERO.** ⇒ ⭐ Y el barrido que nadie corre y que sale gratis: **censar qué avisos citan un ítem YA CERRADO.** -*(En un solo frente había **cuatro** afirmando bloqueos sobre trabajo cerrado la semana anterior —y -el propio corpus tenía escrito el patrón, aplicado a un fichero ajeno y nunca a sí mismo.)* +*(cicatriz `C-101`)* ⛔ **EL VEREDICTO VA EN LA PRIMERA PALABRA DEL CAMPO, NO AL FINAL.** Un campo de estado que **empieza** diciendo *«abierta»* y **termina** en *«✅ cerrada»* es **formalmente correcto y operativamente mentiroso**: quien escanea una columna —que es como se lee una tabla— ve lo primero. Y las dos lecturas son defendibles, así que **dan resultados opuestos y ninguna es refutable**. -*(Medido el 2026-08-29 sobre el semáforo del árbol: **14 filas no empezaban por marca de cierre y -sólo 3 estaban realmente vivas** ⇒ **11 falsos positivos**; y **dos empezaban en «viva» y acababan en -«CERRADA»**. Un censo por el principio las cuenta vivas para siempre; uno que busque «CERRADA», las -cuenta cerradas.)* +*(cicatriz `C-102`)* ⇒ Es la **tercera cara del mismo patrón** en un solo día, y por eso está aquí: **el título de un aviso** acumula los encuadres caídos · **el cierre de una fila** se pone donde cabe en vez de donde se mira · **el veredicto de un campo** se entierra tras 900 caracteres. **Lo que se lee es el @@ -1614,9 +1220,7 @@ primero que cambia**. ⛔ **Y AL VERIFICAR QUE ALGO SOBREVIVE EN OTRO SITIO: UN `id` ES ANCLA DÉBIL — LO QUE DISCRIMINA ES UNA CIFRA DISTINTIVA.** Los ids se citan en todas partes, así que buscarlos da **verde por -construcción**. *(Cicatriz 2026-08-29, verificando 22 filas antes de purgarlas: el primer barrido -por ids —`D12`, `A37`, `A41`…— **las dio las 22 por buenas**. Sólo el careo por **cifra** —`102 s`, -`8 h 14 m`, `suite 1621`— separó las que de verdad tenían su relato fuera.)* +construcción**. *(cicatriz `C-103`)* ⇒ ⭐ Y lo que lo hace un raíl y no una anécdota es **la asimetría**: un patrón demasiado **específico** da **falsos negativos** —molestan, se ven, se corrigen—; un ancla demasiado **común** da **falsos positivos**, y ésos **aprueban un borrado y no se notan nunca**. *«Es peor que tus falsos negativos @@ -1637,9 +1241,7 @@ el hierro la pregunta se hace sola —*¿esto puede romper algo?*—; ante el co porque quien coordina **escribe en él todo el día legítimamente** —avisos, decisiones, bitácora— y una pasada de ordenación **se siente como más de lo mismo**. **No lo es**: reescribe **memoria compartida que leen todas las sesiones**, y por eso su propio procedimiento la declara **única**. -*(Cicatriz 2026-08-29: una orquestadora leyó el workflow de ordenación **entero**, tomó las medidas y -**empezó a hacerlo ella**. Lo correcto era pedir que se abriera esa sesión y pasarle el encargo. La -paró el usuario: «estaba esperando a ver si me sacabas un mensaje para que te abriera una sesión».)* +*(cicatriz `C-104`)* ⇒ ⭐ **El criterio que sí para, y no es ninguno de los dos que se usan por instinto**: no es *«¿sé hacerlo?»* ni *«¿es peligroso?»* — es **«¿esto tiene un TIPO DE SESIÓN PROPIO?»**. Si lo tiene, **se delega aunque sea texto, aunque sea barato y aunque sepas hacerlo**. @@ -1675,12 +1277,7 @@ Diseña qué pasa cuando algo cae, y hazlo verificable. Y si algo se rompe en si - El guard de build falla si falta la copia del bundle, en vez de servir un `