arnés de la imagen: el contador de caídas viaja con la medición, y las envenenadas se apartan

`atuq-en-imagen.py` ahora lee `toolkit.startup.recent_crashes` del perfil ANTES y DESPUÉS de cada
corrida y lo anota junto al tiempo de primera pintura (`recent_crashes_antes` / `_despues` /
`_fijado`). Los dos volcados, no uno: Gecko BORRA el contador al mostrar el diálogo de Modo de
resolución de problemas, así que un perfil envenenado se ve limpio si se lo mira después — y la
corrida siguiente parece arreglarse sola mientras la anterior parece intermitente.

Con eso, `vigia-imagen.py` saca de la tasa las corridas con el contador > 3 (ahí el sujeto no es el
navegador sino un diálogo modal) y para las 21 anteriores al campo dice que NO SE PUEDEN CLASIFICAR
en vez de contarlas como buenas. Un denominador se marca, no se borra.

Mandos y guardas nuevas:

· `--crashes N` fija el contador en el `user.js` del perfil: 0 limpia, >3 reproduce. Es el control en
  los dos sentidos, que es lo único que distingue causa de correlación con suerte;
· `WidgetScreen:5` en el MOZ_LOG y una sonda `ATUQ-DIAG` en la propia página (screen/outer/inner por
  `dump()`), que es lo que refutó la carrera con `wl_output`;
· la lista ordenada del protocolo ya no se ahoga en los ~60 modos que anuncia QEMU —el `head`
  cortaba antes del `set_window_geometry`— y trae `set_title`/`set_app_id`, que es lo que identificó
  la ventana;
· si QEMU no arranca, se dice en el primer segundo leyendo `qemu.log`. El fallo real es «Failed to
  get write lock» con otra VM sobre la misma imagen, y sin esta guarda se veía como diez minutos
  esperando una marca del serial: el socket queda creado y el `connect()` funciona.

Las fases (`--xulstore`), el `ATUQ-EXIT=$?`, la copia del log del arranque anterior y el `find` del
perfil sobre la raíz entera los escribió la otra sesión que trabaja este frente; conviven acá porque
el fichero es compartido.
This commit is contained in:
Sergio
2026-09-15 17:46:30 +00:00
parent 70107b1685
commit 2f90d8eb40
2 changed files with 350 additions and 109 deletions
+26
View File
@@ -286,18 +286,44 @@ def informe_primera_pintura():
and "dos DRM" in (c.get("video") or "")
and c.get("segundos_primera_pintura") is None]
corridas = [c for c in corridas if c not in ciegas]
# ⚠ Y SE SEPARAN LAS CORRIDAS CON EL PERFIL ENVENENADO. Medido el 2026-09-15 (§6.10.terdecies):
# con `toolkit.startup.recent_crashes` por encima de `max_resumed_crashes` —3 por defecto— el
# navegador NO abre una ventana de navegador: abre el diálogo de Modo de resolución de problemas,
# que es modal y mide 117×70. El ✗ de esas corridas es cierto y no dice NADA del producto. Y el
# contador lo subía este mismo andamiaje al matar la VM con el navegador vivo, así que la serie
# vieja está contaminada: las corridas anteriores a que el arnés anotara el campo NO SE PUEDEN
# clasificar, y eso se dice en vez de contarlas como si fueran buenas.
def envenenada(c):
fijado = c.get("recent_crashes_fijado") # lo que PUSO el arnés (user.js gana)
valor = fijado if fijado is not None else c.get("recent_crashes_antes")
return valor is not None and valor > 3
envenenadas = [c for c in corridas if envenenada(c)]
corridas = [c for c in corridas if c not in envenenadas]
sin_clasificar = [c for c in corridas if "recent_crashes_antes" not in c
and c.get("recent_crashes_fijado") is None]
pintaron = [c["segundos_primera_pintura"] for c in corridas
if c.get("segundos_primera_pintura") is not None]
n, m = len(pintaron), len(corridas)
marca = "" if n == m else ("" if n == 0 else "")
if ciegas:
marca = "" # con corridas ciegas de por medio, un 6/6 no es un ✓: es un «lo que se pudo medir»
if sin_clasificar:
marca = "" # una tasa con corridas de procedencia desconocida adentro no es una tasa
if pintaron:
print(" %s pintaron %d de %d corridas CONCLUYENTES · primera pintura %s"
% (marca, n, m,
("+%ds" % pintaron[0]) if n == 1 else "+%d…+%ds" % (min(pintaron), max(pintaron))))
else:
print(" %s NINGUNA de %d corridas pintó" % (marca, m))
if envenenadas:
print("%d corridas APARTE: el perfil tenía recent_crashes > 3 ⇒ lo que abrió fue el "
"diálogo de Modo de resolución de problemas, no el navegador (SDD 26 §6.10.terdecies)"
% len(envenenadas))
if sin_clasificar:
print("%d de esas %d corridas son de ANTES de que se anotara el contador de caídas: "
"no se puede decir si midieron el navegador o el diálogo" % (len(sin_clasificar), m))
for c in corridas[-6:]:
seg = c.get("segundos_primera_pintura")
print(" %s %-9s %-10s %-22s %-26s %s"