Cada arnés headless tenía su propio subconjunto de MOZ_DISABLE_*_SANDBOX, elegido en su
momento sin medir: banco 1 de 5, perfilar 4, codecs 3, ruteo 3, nativo 2, inicio 2. Con
cualquier subconjunto incompleto el sandbox de Firefox sigue intentando montar su
user-namespace dentro del de bwrap, falla con 'uid_map: EPERM' y deja un ayudante
'Sandbox Forked' muerto de SIGSEGV por cada intento — en el 100% de las corridas, después
de escribir el PNG y por eso invisible.
Medido: 2 cadáveres por corrida con sólo CONTENT apagado, 0 con los cinco. Verificado sobre
el arnés ya editado: segv=0 EPERM=0 screenshot=sí.
Acá no se pierde seguridad: bwrap ya es la jaula, el sandbox de Gecko es redundante y lo
único que hace dentro es fallar.
⚠ Cambia las condiciones de medición del banco de PGO: las cifras de docs/26 se tomaron con
el arnés viejo. Los cocientes del PGO comparan dos firefox bajo el mismo arnés y deberían
aguantar; la línea base absoluta de arranque no tiene por qué. Anotado en la cabecera.
No se tocan scripts/wlr/dunst-headless.sh (otro agente trabajando en él) ni los cazadores,
que conservan el entorno viejo a propósito para poder reproducir la condición original.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QPJteswQvP1L7zSBrQQe2
Estaba en un scratchpad y se perdía; ahora vive en el repo con el porqué de cada
guarda, porque las tres se pagaron durante la primera corrida:
1. --unshare-pid en el bwrap. Sin él los hijos SOBREVIVEN al sandbox: un
http.server quedó vivo 19 HORAS, retuvo el puerto y envenenó las corridas
siguientes con «Address in use».
2. Puerto aleatorio por corrida. Elimina la colisión de raíz en vez de
detectarla: si otro proceso tiene un puerto, este arranque usa otro.
3. Marcador único por corrida, servido desde una copia ESCRIBIBLE del corpus.
La versión anterior horneaba el marcador como constante del script, y eso
rompía justo lo que el chequeo existe para probar: el servidor huérfano
servía el MISMO fichero de marca y el chequeo lo daba por bueno. Verificaba
«alguien sirve este contenido», no «este servidor es el mío». Con el marcador
por corrida, un servidor ajeno devuelve otra cosa y se aborta.
Y queda escrito por qué los sandboxes de Firefox van apagados en el
entrenamiento: con ellos los hijos mueren con signal 11, el proceso que renderiza
no nace, el servidor registra 0 GET y el único .profraw es el del padre
arrancando — un perfil de nada, con todo en verde. Es lo que hace el
profileserver.py de Mozilla. Sólo aplica al entrenamiento.
La espera al servidor va con reintento y no con un sleep fijo: 2 s concluían
«no responde» sobre uno que sí iba a responder.
Medida la ganancia del PGO ayer: -9,4% en una página de DOM/maquetación y -1,0%
en 3d-raytrace de SunSpider. La razón de la diferencia es que un benchmark
JIT-bound es casi CIEGO al PGO: el bucle caliente no lo ejecuta el C++ de
SpiderMonkey sino el código máquina que el JIT emite en runtime, y el PGO
optimiza el intérprete, el GC y el propio JIT — no lo que el JIT produce.
El corpus de Mozilla está dominado en número de páginas por SunSpider, o sea que
entrenaba mucho justo donde el PGO menos rinde. Estas diez ejercitan el camino
que sí es C++ de punta a punta:
flex flexbox anidado, wrap, alineaciones
rejilla CSS Grid: pistas, áreas nombradas, auto-fit
tablas tablas grandes con table-layout FIJO y AUTO (dos algoritmos)
texto columnas, shaping, reflujo por cambio de ancho
selectores DOM profundo contra 600 reglas, muchas que NO casan
pintado degradados, sombras, opacidad, mix-blend-mode
transformar transforms y contextos de apilamiento
svg paths, degradados, clip
desbordes overflow anidado, position:sticky, scroll programático
reflujo layout thrashing: leer y escribir geometría alternadamente
Reglas que cumplen todas, y no son de estilo:
· DETERMINISTAS (LCG propio, ni Math.random ni Date ni red) — dos corridas hacen
lo mismo, así que dos perfiles difieren por el timing de los contadores y no
por haber visitado caminos distintos.
· AUTOCONTENIDAS — el perfilado corre sin red.
· NUESTRAS — nada de páginas ajenas capturadas, que traerían licencia y
fragilidad.
· ACOTADAS — 16 a 32 s cada una; el perfilado arranca un navegador POR PÁGINA.
Validadas las diez contra el firefox sellado: todas renderizan y producen
captura. `flex` hubo que acortarla de 40 a 12 cajas raíz: con 40 la página medía
68.241 px de alto y la captura moría con «Failed to allocate a surface due to
invalid size». El layout ocurría igual, pero sin captura no se ejercita el
pintado, que es justo la mitad que se venía a entrenar.