<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es">
    <title>storagebits</title>
    <subtitle>Firmware, apps de TV, un homelab, construidos de noche con una organización de agentes de IA. Y blok, el cuaderno de taller.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://blok.storagebits.workers.dev/es/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blok.storagebits.workers.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-10-18T18:05:17-04:00</updated>
    <id>https://blok.storagebits.workers.dev/es/atom.xml</id>
    <entry xml:lang="es">
        <title>Probando la NUCLEO-F412ZG con Hubris y Humility</title>
        <published>2026-10-18T18:05:17-04:00</published>
        <updated>2026-10-18T18:05:17-04:00</updated>
        <author><name>François</name></author>
        <link rel="alternate" type="text/html" href="https://blok.storagebits.workers.dev/es/blog/hubris-f412/"/>
        <id>https://blok.storagebits.workers.dev/es/blog/hubris-f412/</id>
        <summary type="html">Portar Hubris, el sistema operativo embebido de Oxide Computer, a una NUCLEO-F412ZG a 100 MHz: lo que hubo que tocar, del kernel intacto a los dos parches de Humility, explicado.</summary>
        <content type="html" xml:base="https://blok.storagebits.workers.dev/es/blog/hubris-f412/">&lt;p&gt;El tema: una NUCLEO-F412ZG, una placa de desarrollo de ST con un Cortex-M4, y &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https://github.com/oxidecomputer/hubris&quot;&gt;Hubris&lt;/a&gt;, el sistema operativo embebido de Oxide Computer, que no la soporta de serie. El kernel no cambió ni una línea. Hubo que añadir la placa, adaptar tres drivers, actualizar el firmware de la sonda y corregir dos veces Humility, el depurador.&lt;/p&gt;
&lt;figure class=&quot;portrait&quot;&gt;&lt;img src=&quot;nucleo-f412zg.webp&quot; alt=&quot;La placa NUCLEO-F412ZG sobre una alfombrilla negra, conectada por USB, con sus LED de usuario verde, azul y rojo encendidos.&quot; width=&quot;1125&quot; height=&quot;1500&quot; loading=&quot;lazy&quot;&gt;&lt;figcaption&gt;La NUCLEO-F412ZG, alimentada por el USB del ST-LINK, la sonda integrada en la parte inferior de la placa. Encima, los tres LED de usuario que controla la tarea pong.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;hubris-humility-que-son-quien-esta-detras&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hubris-humility-que-son-quien-esta-detras&quot; aria-label=&quot;Anchor link for: hubris-humility-que-son-quien-esta-detras&quot;&gt;#&lt;/a&gt;
Hubris, Humility: ¿qué son? ¿Quién está detrás?&lt;/h2&gt;
&lt;p&gt;Hubris es un pequeño sistema operativo en Rust que Oxide usa en sus servidores para el procesador de servicio. Cada tarea vive en sus propias regiones de memoria, protegidas por la MPU. Las tareas, sus prioridades y sus permisos sobre los periféricos se declaran todos en tiempo de compilación, en un &lt;code&gt;app.toml&lt;/code&gt;. Humility lee la memoria de la placa a través de la sonda y la traduce gracias a la información de depuración: estado de las tareas, pilas, registros, volcados.&lt;/p&gt;
&lt;p&gt;El autor principal es Cliff Biffle. Su charla en la Open Source Firmware Conference 2021 explica por qué Oxide escribió su propio sistema operativo. Esta charla es realmente increíble, ¡qué gran obra de ingeniería!&lt;/p&gt;
&lt;figure class=&quot;video video-externe video-large&quot;&gt;&lt;iframe src=&quot;https://player.vimeo.com/video/650913348?dnt=1&quot; title=&quot;On Hubris and Humility, Cliff L. Biffle, OSFC 2021&quot; loading=&quot;lazy&quot; allow=&quot;fullscreen; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;figcaption&gt;«On Hubris and Humility: developing an OS for robustness in Rust», Cliff L. Biffle, Open Source Firmware Conference 2021, 43 min.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;También hay que citar a Bryan Cantrill, cofundador y CTO de Oxide, y a Adam Leventhal entre los grandes nombres detrás de Hubris. En su charla sobre la depuración de Docker en producción, en la DockerCon 2015, Cantrill defiende una idea sencilla: un sistema colgado no se reinicia antes de haberlo depurado, en vivo o a partir de una imagen de su memoria, el &lt;em&gt;core dump&lt;/em&gt;. Humility hace las dos cosas: &lt;code&gt;humility tasks&lt;/code&gt; lee la placa en marcha y &lt;code&gt;humility dump&lt;/code&gt; guarda su estado completo en un archivo que se examina después, con la placa desconectada.&lt;/p&gt;
&lt;figure class=&quot;video video-externe video-large&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/AdMqCUhvRz8&quot; title=&quot;Running Aground: Debugging Docker in Production, Bryan Cantrill, DockerCon 2015&quot; loading=&quot;lazy&quot; allow=&quot;fullscreen; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;figcaption&gt;«Running Aground: Debugging Docker in Production», Bryan Cantrill, DockerCon 2015. Docker retiró el vídeo original en 2018; esta es la copia que volvió a publicar Cantrill.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;lo-que-hubo-que-parchear&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lo-que-hubo-que-parchear&quot; aria-label=&quot;Anchor link for: lo-que-hubo-que-parchear&quot;&gt;#&lt;/a&gt;
Lo que hubo que parchear&lt;/h2&gt;
&lt;p&gt;Le paso a Claude un prompt de misión: hacer funcionar Hubris en esta placa, conectada por USB al Mac. Su objetivo más cercano en el repositorio es una placa Discovery con un STM32F407. Esa misma noche, Hubris corre a 100 MHz en la NUCLEO.&lt;/p&gt;
&lt;p&gt;Lo que se parcheó, capa por capa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;El kernel&lt;/strong&gt;: nada, ni una línea.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;La placa y la app&lt;/strong&gt;: solo añadidos. Un archivo de placa de 2 líneas (el nombre del chip para probe-rs), una descripción del chip (1 MiB de flash, 256 KiB de RAM, direcciones de los periféricos) y la app en sí, con la configuración de reloj a 100 MHz. La rama añade 621 líneas, documentación incluida.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tres drivers compartidos&lt;/strong&gt;, unas 150 líneas: &lt;code&gt;stm32fx-rcc&lt;/code&gt; elige la variante F412 de la biblioteca de registros, &lt;code&gt;user-leds&lt;/code&gt; controla los LED de la Nucleo en PB0, PB7 y PB14, y &lt;code&gt;stm32fx-usart&lt;/code&gt; pasa a USART3 (PD8/PD9), el puerto serie virtual del ST-LINK, a 50 MHz. El punto delicado: dos variantes de chip del crate &lt;code&gt;stm32f4&lt;/code&gt; no pueden convivir en una misma tarea, y dos de estos drivers forzaban la F407 en su &lt;code&gt;Cargo.toml&lt;/code&gt;. Esa elección pasó a una feature. La Discovery compila exactamente igual, comprobado de nuevo en cada paso.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;La sonda&lt;/strong&gt;: el firmware del ST-LINK, demasiado antiguo, tuvo que actualizarse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Humility&lt;/strong&gt;, el depurador: dos parches, detallados más abajo. El primero arregla Humility frente al Hubris más reciente, sea cual sea la placa. El segundo corrige una medida errónea que aparece en esta placa.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;la-mision-por-tramos&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#la-mision-por-tramos&quot; aria-label=&quot;Anchor link for: la-mision-por-tramos&quot;&gt;#&lt;/a&gt;
La misión, por tramos&lt;/h2&gt;
&lt;p&gt;La north star del prompt cabe en una frase: «&lt;code&gt;humility tasks&lt;/code&gt; montre toutes les tâches &lt;code&gt;Healthy&lt;/code&gt; sur la NUCLEO-F412ZG, les LEDs utilisateur clignotent sous le contrôle de &lt;code&gt;pong&lt;/code&gt;, et &lt;code&gt;ping&lt;/code&gt; écrit sur le port COM virtuel du ST-LINK.» [&lt;code&gt;humility tasks&lt;/code&gt; muestra todas las tareas &lt;code&gt;Healthy&lt;/code&gt; en la NUCLEO-F412ZG, los LED de usuario parpadean bajo el control de &lt;code&gt;pong&lt;/code&gt;, y &lt;code&gt;ping&lt;/code&gt; escribe en el puerto COM virtual del ST-LINK.] Cinco tramos, cada uno debe terminar en hardware que funciona: preflight, build de referencia, primer arranque con el oscilador interno a 16 MHz, UART y luego 100 MHz.&lt;/p&gt;
&lt;p&gt;Primera parada ya en el tramo 0. El firmware del ST-LINK de la placa está en V2J25; probe-rs, en el que se apoya Humility, exige J26. El prompt decía que había que pararse y preguntar. Claude propone parchearlo automáticamente, le doy el zip descargado de la web de ST y listo.&lt;/p&gt;
&lt;p&gt;Todas las tareas están &lt;code&gt;Healthy&lt;/code&gt;. Claude no ve los LED: lee el registro de salida de GPIOB varias veces seguidas y lo ve alternar entre PB14, PB0 y nada, al ritmo de &lt;code&gt;pong&lt;/code&gt;. La placa corre a 100 MHz. En 10 segundos, el reloj de Hubris cuenta 10 235 ms frente a 10,32 s de reloj de pared; la diferencia es la latencia de conexión de Humility.&lt;/p&gt;
&lt;figure class=&quot;sys sys-horloge&quot;&gt;&lt;div class=&quot;defile&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Árbol de reloj de la NUCLEO-F412ZG a 100 MHz, desplazable horizontalmente&quot;&gt;&lt;svg viewBox=&quot;0 0 760 300&quot; role=&quot;img&quot; aria-labelledby=&quot;horloge-t horloge-d&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;title id=&quot;horloge-t&quot;&gt;Árbol de reloj de la NUCLEO-F412ZG a 100 MHz&lt;/title&gt;&lt;desc id=&quot;horloge-d&quot;&gt;El MCO del ST-LINK entrega 8 MHz a la entrada HSE bypass. PLLM 4 da 2 MHz, PLLN 100 da un VCO a 200 MHz, PLLP 2 da un SYSCLK a 100 MHz. AHB a 100 MHz, APB1 a 50 MHz para la USART3, APB2 a 100 MHz.&lt;/desc&gt;&lt;defs&gt;&lt;marker id=&quot;hl-fl&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;&lt;path class=&quot;sys-pointe&quot; d=&quot;M0,0 L10,5 L0,10 z&quot;/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;10&quot; y=&quot;40&quot; width=&quot;118&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;69&quot; y=&quot;60&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;ST-LINK MCO&lt;/text&gt;&lt;text x=&quot;69&quot; y=&quot;84&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;8 MHz&lt;/text&gt;&lt;text x=&quot;69&quot; y=&quot;103&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;onda cuadrada, no un cristal&lt;/text&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;158&quot; y=&quot;40&quot; width=&quot;118&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;217&quot; y=&quot;60&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;HSE bypass&lt;/text&gt;&lt;text x=&quot;217&quot; y=&quot;84&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;8 MHz&lt;/text&gt;&lt;text x=&quot;217&quot; y=&quot;103&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;HSEBYP antes que HSEON&lt;/text&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;306&quot; y=&quot;40&quot; width=&quot;118&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;365&quot; y=&quot;60&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;PLLM = 4&lt;/text&gt;&lt;text x=&quot;365&quot; y=&quot;84&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;2 MHz&lt;/text&gt;&lt;text x=&quot;365&quot; y=&quot;103&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;entrada VCO 1–2 MHz&lt;/text&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;454&quot; y=&quot;40&quot; width=&quot;118&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;513&quot; y=&quot;60&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;PLLN = 100&lt;/text&gt;&lt;text x=&quot;513&quot; y=&quot;84&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;200 MHz&lt;/text&gt;&lt;text x=&quot;513&quot; y=&quot;103&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;VCO 100–432 MHz&lt;/text&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;602&quot; y=&quot;40&quot; width=&quot;148&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;676&quot; y=&quot;60&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;PLLP = 2&lt;/text&gt;&lt;text x=&quot;676&quot; y=&quot;84&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;100 MHz&lt;/text&gt;&lt;text x=&quot;676&quot; y=&quot;103&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;SYSCLK, max F412&lt;/text&gt;&lt;line class=&quot;sys-fil sys-courant&quot; x1=&quot;128&quot; y1=&quot;77&quot; x2=&quot;156&quot; y2=&quot;77&quot; marker-end=&quot;url(#hl-fl)&quot;/&gt;&lt;line class=&quot;sys-fil sys-courant&quot; x1=&quot;276&quot; y1=&quot;77&quot; x2=&quot;304&quot; y2=&quot;77&quot; marker-end=&quot;url(#hl-fl)&quot;/&gt;&lt;line class=&quot;sys-fil sys-courant&quot; x1=&quot;424&quot; y1=&quot;77&quot; x2=&quot;452&quot; y2=&quot;77&quot; marker-end=&quot;url(#hl-fl)&quot;/&gt;&lt;line class=&quot;sys-fil sys-courant&quot; x1=&quot;572&quot; y1=&quot;77&quot; x2=&quot;600&quot; y2=&quot;77&quot; marker-end=&quot;url(#hl-fl)&quot;/&gt;&lt;path class=&quot;sys-fil sys-courant&quot; d=&quot;M676,114 V150 H160 V196&quot; marker-end=&quot;url(#hl-fl)&quot;/&gt;&lt;path class=&quot;sys-fil sys-courant&quot; d=&quot;M390,150 V196&quot; marker-end=&quot;url(#hl-fl)&quot;/&gt;&lt;path class=&quot;sys-fil sys-courant&quot; d=&quot;M620,150 V196&quot; marker-end=&quot;url(#hl-fl)&quot;/&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;60&quot; y=&quot;200&quot; width=&quot;200&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;160&quot; y=&quot;220&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;AHB ÷1&lt;/text&gt;&lt;text x=&quot;160&quot; y=&quot;244&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;100 MHz&lt;/text&gt;&lt;text x=&quot;160&quot; y=&quot;263&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;núcleo, SysTick: 100 000 ciclos/ms&lt;/text&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;290&quot; y=&quot;200&quot; width=&quot;200&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;390&quot; y=&quot;220&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;APB1 ÷2&lt;/text&gt;&lt;text x=&quot;390&quot; y=&quot;244&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;50 MHz&lt;/text&gt;&lt;text x=&quot;390&quot; y=&quot;263&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;USART3: BRR 434 → 115 207 baudios&lt;/text&gt;&lt;rect class=&quot;sys-boite&quot; x=&quot;520&quot; y=&quot;200&quot; width=&quot;200&quot; height=&quot;74&quot; rx=&quot;6&quot;/&gt;&lt;text x=&quot;620&quot; y=&quot;220&quot; class=&quot;sys-titre&quot; text-anchor=&quot;middle&quot;&gt;APB2 ÷1&lt;/text&gt;&lt;text x=&quot;620&quot; y=&quot;244&quot; class=&quot;sys-valeur&quot; text-anchor=&quot;middle&quot;&gt;100 MHz&lt;/text&gt;&lt;text x=&quot;620&quot; y=&quot;263&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;max 100 MHz&lt;/text&gt;&lt;text x=&quot;380&quot; y=&quot;24&quot; class=&quot;sys-note&quot; text-anchor=&quot;middle&quot;&gt;Flash: 3 wait states (90 &amp;lt; HCLK ≤ 100 MHz a 2,7–3,6 V) · regulador en scale 1&lt;/text&gt;&lt;text x=&quot;380&quot; y=&quot;296&quot; class=&quot;sys-code&quot; text-anchor=&quot;middle&quot;&gt;Releído en la placa: RCC_PLLCFGR = 0x28401904 · RCC_CFGR = 0x100a · FLASH_ACR = 0x703&lt;/text&gt;&lt;/svg&gt;&lt;/div&gt;&lt;figcaption&gt;El tramo 4: de 16 MHz con el HSI a 100 MHz. Cada constante está justificada en el código por una sección del RM0402, y releída en los registros una vez flasheada.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;cuando-se-rompio-savedstate&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cuando-se-rompio-savedstate&quot; aria-label=&quot;Anchor link for: cuando-se-rompio-savedstate&quot;&gt;#&lt;/a&gt;
Cuando se rompió: SavedState&lt;/h2&gt;
&lt;p&gt;Justo antes del primer arranque, &lt;code&gt;humility tasks&lt;/code&gt; falla: «expected structure SavedState not found».&lt;/p&gt;
&lt;p&gt;Para entenderlo, hay que saber cómo lee Humility una tarea. Cuando el kernel interrumpe una tarea, guarda sus registros (r4 a r11, el puntero de pila, etc.) en una estructura, el campo &lt;code&gt;save&lt;/code&gt; de la entrada &lt;code&gt;Task&lt;/code&gt; de esa tarea. Humility lee la tabla de tareas directamente en la RAM de la placa. Para saber en qué byte está cada registro, necesita el plano de esa estructura, que encuentra en la información de depuración (DWARF) del binario del kernel. Y la buscaba por su nombre: &lt;code&gt;SavedState&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;El 9 de octubre, cuatro días antes, la PR #2704 de Hubris introdujo un trait &lt;code&gt;Arch&lt;/code&gt; para que el kernel pueda apuntar a varias arquitecturas. La estructura del ARMv7-M pasó a llamarse &lt;code&gt;ArmMSavedState&lt;/code&gt;. Humility ya no la encuentra, y ni &lt;code&gt;humility tasks&lt;/code&gt; ni la lectura de los registros de una tarea funcionan, sea cual sea la placa.&lt;/p&gt;
&lt;p&gt;Dos maneras de salir del paso. Claude primero fija la rama justo antes de ese commit y sigue adelante, lo que basta para esta placa. Está en DECISIONS.md, y desbloquea. Después, el parche, en la rama &lt;code&gt;savedstate-by-member&lt;/code&gt; de mi fork de Humility: en lugar de buscar el tipo por su nombre, Humility toma el tipo del campo &lt;code&gt;save&lt;/code&gt; de &lt;code&gt;Task&lt;/code&gt;, que DWARF da directamente. El nombre puede cambiar; el campo se queda. Once líneas añadidas, cuatro eliminadas, en los dos sitios que leían esa estructura: &lt;code&gt;humility tasks&lt;/code&gt; y la lectura de los registros. El parche funciona con el kernel antiguo y con el nuevo, probado en la placa en ambos casos.&lt;/p&gt;
&lt;h2 id=&quot;el-segundo-parche-stackmargin-mostraba-ceros&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#el-segundo-parche-stackmargin-mostraba-ceros&quot; aria-label=&quot;Anchor link for: el-segundo-parche-stackmargin-mostraba-ceros&quot;&gt;#&lt;/a&gt;
El segundo parche: stackmargin mostraba ceros&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;humility stackmargin&lt;/code&gt; indica, para cada tarea, cuánta pila no ha usado nunca. El principio: al arrancar una tarea, el kernel llena toda su pila con un patrón, &lt;code&gt;0xbaddcafe&lt;/code&gt;. Humility lee la pila desde abajo y cuenta las palabras que siguen intactas: ese es el margen.&lt;/p&gt;
&lt;p&gt;En la placa, muestra un margen de 0 para &lt;code&gt;jefe&lt;/code&gt;, el supervisor, con una pila de 152 bytes, cuando su &lt;code&gt;app.toml&lt;/code&gt; declara 2200.&lt;/p&gt;
&lt;p&gt;La MPU de un Cortex-M4 solo admite regiones cuyo tamaño es una potencia de 2. Desde abril (PR #2458), Hubris divide la RAM de una tarea en varias regiones contiguas para desperdiciar menos: los 2560 bytes de &lt;code&gt;jefe&lt;/code&gt; son 1 KiB + 1 KiB + 512 bytes en lugar de una única región de 4 KiB. Así que una pila puede extenderse por varias regiones. El kernel se corrigió en mayo (PR #2492) para pintarla entera. Humility, en cambio, solo leía la región que contiene la cima de la pila: aquí la última, donde caben solo 152 bytes de pila, todos usados. De ahí el margen de 0.&lt;/p&gt;
&lt;figure class=&quot;sys sys-pile&quot;&gt;&lt;div class=&quot;defile&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;La pila de jefe vista por humility stackmargin, antes y después del parche, desplazable horizontalmente&quot;&gt;&lt;svg viewBox=&quot;0 0 800 300&quot; role=&quot;img&quot; aria-labelledby=&quot;pile-t pile-d&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;title id=&quot;pile-t&quot;&gt;La pila de jefe vista por humility stackmargin, antes y después del parche&lt;/title&gt;&lt;desc id=&quot;pile-d&quot;&gt;La RAM de jefe ocupa 2560 bytes repartidos en tres regiones MPU contiguas. Su pila de 2200 bytes empieza en 0x20001400 y su cima inicial es 0x20001C98, en la tercera región. Antes del parche, Humility solo leía esa tercera región: 152 bytes, todos usados, así que un margen de 0. Después del parche, lee los 2200 bytes, encuentra 1928 bytes todavía a 0xbaddcafe y un margen de 1928.&lt;/desc&gt;&lt;defs&gt;&lt;pattern id=&quot;pl-peint&quot; width=&quot;6&quot; height=&quot;6&quot; patternUnits=&quot;userSpaceOnUse&quot; patternTransform=&quot;rotate(45)&quot;&gt;&lt;line class=&quot;sys-hachure&quot; x1=&quot;0&quot; y1=&quot;0&quot; x2=&quot;0&quot; y2=&quot;6&quot;/&gt;&lt;/pattern&gt;&lt;/defs&gt;&lt;rect class=&quot;sys-peint-fond&quot; x=&quot;70.0&quot; y=&quot;54&quot; width=&quot;482.0&quot; height=&quot;44&quot;/&gt;&lt;rect fill=&quot;url(#pl-peint)&quot; x=&quot;70.0&quot; y=&quot;54&quot; width=&quot;482.0&quot; height=&quot;44&quot;/&gt;&lt;rect class=&quot;sys-utilise&quot; x=&quot;552.0&quot; y=&quot;54&quot; width=&quot;68.0&quot; height=&quot;44&quot;/&gt;&lt;rect class=&quot;sys-donnees&quot; x=&quot;620.0&quot; y=&quot;54&quot; width=&quot;90.0&quot; height=&quot;44&quot;/&gt;&lt;text x=&quot;198&quot; y=&quot;81&quot; class=&quot;sys-dans&quot; text-anchor=&quot;middle&quot;&gt;0xbaddcafe: 1928 B sin tocar&lt;/text&gt;&lt;text x=&quot;665&quot; y=&quot;81&quot; class=&quot;sys-dans&quot; text-anchor=&quot;middle&quot;&gt;datos&lt;/text&gt;&lt;rect class=&quot;sys-region&quot; x=&quot;70.0&quot; y=&quot;54&quot; width=&quot;256.0&quot; height=&quot;44&quot;/&gt;&lt;text x=&quot;198&quot; y=&quot;44&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;región 1 · 1 KiB&lt;/text&gt;&lt;rect class=&quot;sys-region&quot; x=&quot;326.0&quot; y=&quot;54&quot; width=&quot;256.0&quot; height=&quot;44&quot;/&gt;&lt;text x=&quot;454&quot; y=&quot;44&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;región 2 · 1 KiB&lt;/text&gt;&lt;rect class=&quot;sys-region&quot; x=&quot;582.0&quot; y=&quot;54&quot; width=&quot;128.0&quot; height=&quot;44&quot;/&gt;&lt;text x=&quot;646&quot; y=&quot;44&quot; class=&quot;sys-detail&quot; text-anchor=&quot;middle&quot;&gt;región 3 · 512 B&lt;/text&gt;&lt;line class=&quot;sys-repere&quot; x1=&quot;620.0&quot; y1=&quot;50&quot; x2=&quot;620.0&quot; y2=&quot;168&quot;/&gt;&lt;text x=&quot;624&quot; y=&quot;120&quot; class=&quot;sys-code&quot;&gt;cima inicial 0x20001C98&lt;/text&gt;&lt;line class=&quot;sys-repere&quot; x1=&quot;552.0&quot; y1=&quot;98&quot; x2=&quot;552.0&quot; y2=&quot;108&quot;/&gt;&lt;text x=&quot;548&quot; y=&quot;120&quot; class=&quot;sys-detail&quot; text-anchor=&quot;end&quot;&gt;272 B usados&lt;/text&gt;&lt;text x=&quot;70&quot; y=&quot;290&quot; class=&quot;sys-axe&quot; text-anchor=&quot;middle&quot;&gt;0x20001400&lt;/text&gt;&lt;text x=&quot;326&quot; y=&quot;290&quot; class=&quot;sys-axe&quot; text-anchor=&quot;middle&quot;&gt;0x20001800&lt;/text&gt;&lt;text x=&quot;582&quot; y=&quot;290&quot; class=&quot;sys-axe&quot; text-anchor=&quot;middle&quot;&gt;0x20001C00&lt;/text&gt;&lt;text x=&quot;710&quot; y=&quot;290&quot; class=&quot;sys-axe&quot; text-anchor=&quot;middle&quot;&gt;0x20001E00&lt;/text&gt;&lt;text x=&quot;10&quot; y=&quot;174&quot; class=&quot;sys-serie sys-faute-txt&quot;&gt;antes&lt;/text&gt;&lt;line class=&quot;sys-mesure sys-faute&quot; x1=&quot;582.0&quot; y1=&quot;170&quot; x2=&quot;620.0&quot; y2=&quot;170&quot;/&gt;&lt;circle class=&quot;sys-scan sys-scan-avant&quot; cx=&quot;582.0&quot; cy=&quot;170&quot; r=&quot;5&quot;/&gt;&lt;text x=&quot;574&quot; y=&quot;174&quot; class=&quot;sys-detail&quot; text-anchor=&quot;end&quot;&gt;lee 152 B, se detiene en la 1.ª palabra → MARGIN 0&lt;/text&gt;&lt;text x=&quot;10&quot; y=&quot;219&quot; class=&quot;sys-serie sys-sain-txt&quot;&gt;después&lt;/text&gt;&lt;line class=&quot;sys-mesure sys-sain&quot; x1=&quot;70.0&quot; y1=&quot;215&quot; x2=&quot;620.0&quot; y2=&quot;215&quot;/&gt;&lt;g class=&quot;sys-scan-apres&quot;&gt;&lt;circle class=&quot;sys-scan&quot; cx=&quot;70.0&quot; cy=&quot;215&quot; r=&quot;5&quot;/&gt;&lt;/g&gt;&lt;text x=&quot;70&quot; y=&quot;237&quot; class=&quot;sys-detail&quot;&gt;lee 2200 B desde la base, cuenta 1928 B de 0xbaddcafe → MARGIN 1928&lt;/text&gt;&lt;/svg&gt;&lt;/div&gt;&lt;figcaption&gt;Leído en la placa (humility map, readmem). Humility solo miraba la región que contiene la cima de la pila. El kernel, en cambio, pinta toda la pila con 0xbaddcafe en las tres regiones.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            STACKBASE  STACKSIZE  MAXDEPTH  MARGIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;antes   jefe 0x20001c00       152       152       0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;después jefe 0x20001400      2200       272    1928&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;El parche, en la rama &lt;code&gt;stackmargin-multi-region&lt;/code&gt;, recorre hacia abajo las regiones contiguas que pertenecen a la misma tarea, como hace el kernel, antes de medir. La prueba de no regresión de Humility también lo validó: en un volcado de un Sidecar, un switch real de Oxide, la instantánea esperada contenía tres falsos «MARGIN 0». Tras la corrección, cada tamaño de pila coincide al byte con el declarado en el &lt;code&gt;app.toml&lt;/code&gt; de ese Sidecar.&lt;/p&gt;
&lt;h2 id=&quot;donde-estoy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#donde-estoy&quot; aria-label=&quot;Anchor link for: donde-estoy&quot;&gt;#&lt;/a&gt;
Dónde estoy&lt;/h2&gt;
&lt;p&gt;La rama &lt;code&gt;nucleo-f412zg&lt;/code&gt; tiene cinco commits, con un DECISIONS.md y un README. Está fijada antes de la PR #2704; con el primer parche, Humility también sigue al kernel reciente. Los dos parches están en mi fork de Humility. La batería de pruebas del kernel en la F412, el tramo 5 opcional, no está hecha. Y «todo &lt;code&gt;Healthy&lt;/code&gt;» solo es verdad a medias: &lt;code&gt;ping&lt;/code&gt; provoca a propósito un fallo cada 100 respuestas de &lt;code&gt;pong&lt;/code&gt;, como en las demos de Oxide.&lt;/p&gt;
&lt;p&gt;Una pista para más adelante, aún sin hacer: un sensor I2C o SPI detrás de una tarea driver. En Hubris, un driver es una tarea como cualquier otra: solo ella tiene acceso a los registros del periférico, declarados en el &lt;code&gt;app.toml&lt;/code&gt;, y las demás tareas le hablan mediante mensajes. El driver I2C del repositorio apunta a los STM32H7 y G0 (más un driver aparte para el LPC55), el SPI solo a los STM32H7 y al LPC55: nada para la familia F4, habría que escribirlo para esta placa.&lt;/p&gt;
&lt;p&gt;Continuará…&lt;/p&gt;
&lt;aside class=&quot;transparence&quot; aria-label=&quot;Cómo se escribió esta entrada&quot;&gt;
  &lt;p class=&quot;transparence-titre&quot;&gt;Cómo se escribió esta entrada&lt;/p&gt;
  &lt;p&gt;Redactada por Claude Opus 5.5 a partir de: un prompt de misión, una decena de mensajes y una entrevista escritos por François, su sesión de Claude Code, el repositorio &lt;code&gt;hubris&lt;/code&gt; (5 commits en la rama &lt;code&gt;nucleo-f412zg&lt;/code&gt;), dos ramas de Humility (3 commits), las salidas de &lt;code&gt;humility&lt;/code&gt; y los registros releídos en la placa.&lt;/p&gt;
  &lt;p&gt;Revisada y corregida por François en 20 min, 6 % del texto reescrito.&lt;/p&gt;
  &lt;p&gt;Traducida del francés por la IA, a partir de la versión revisada. La traducción no se revisó línea por línea.&lt;/p&gt;
&lt;/aside&gt;
</content>
    </entry>
    <entry xml:lang="es">
        <title>Un reloj de 2020, un firmware completo, tres días</title>
        <published>2026-10-16T00:00:00+00:00</published>
        <updated>2026-10-16T00:00:00+00:00</updated>
        <author><name>François</name></author>
        <link rel="alternate" type="text/html" href="https://blok.storagebits.workers.dev/es/blog/ressusciter-kronograf/"/>
        <id>https://blok.storagebits.workers.dev/es/blog/ressusciter-kronograf/</id>
        <summary type="html">Un T-Watch de 2020 dormía en un rincón: desarrollar para él exigía demasiado esfuerzo. En tres días, con un agente, recibió un firmware escrito desde cero y publicado con licencia MIT.</summary>
        <content type="html" xml:base="https://blok.storagebits.workers.dev/es/blog/ressusciter-kronograf/">&lt;p&gt;Compré un LilyGO T-Watch 2020 hace seis años, porque era barato e ideal para probar y trastear. Desarrollar para él, en cambio, exigía una inversión real: C/C++, un framework que aprender, nociones de sistemas embebidos. Acabó en un rincón, junto a otros side projects sin terminar.&lt;/p&gt;
&lt;p&gt;Con la IA, todos esos frenos desaparecen: en pocos minutos, tenía un firmware completo, escrito desde cero. Sin la IA, no lo habría sacado del cajón: crear cualquier cosa en él exigía demasiado esfuerzo.&lt;/p&gt;
&lt;p&gt;¿Qué aparatos duermen en tu casa? Imagina lo que podrías hacer con ellos, en un tiempo récord.&lt;/p&gt;
&lt;p&gt;La &lt;a href=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/&quot;&gt;entrada sobre los cuatro días&lt;/a&gt; ya contó el primer flasheo. Aquí me quedo con el reloj.&lt;/p&gt;
&lt;h2 id=&quot;lo-que-queria&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lo-que-queria&quot; aria-label=&quot;Anchor link for: lo-que-queria&quot;&gt;#&lt;/a&gt;
Lo que quería&lt;/h2&gt;
&lt;p&gt;Una esfera de cronógrafo de aviación y displays de 7 segmentos al estilo de los «circuitos temporales». Luego el tiempo, los autobuses y las notificaciones del iPhone. La lista completa de aplicaciones está en el README del repositorio.&lt;/p&gt;
&lt;p&gt;Mi método se resume en dos gestos. Expongo sencillamente las funciones que quiero. Luego pido enseguida una primera versión de principio a fin, para tener un ciclo de retroalimentación corto. El resultado se vuelve convincente muy rápido.&lt;/p&gt;
&lt;p&gt;Dirigí el desarrollo en lenguaje natural, expresando intenciones. Leyendo el código generado, también aprendí mucho, tanto sobre el lenguaje como sobre los frameworks y los conceptos de sistemas embebidos. ¡El alcance pedagógico es inmenso!&lt;/p&gt;
&lt;h2 id=&quot;el-comienzo&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#el-comienzo&quot; aria-label=&quot;Anchor link for: el-comienzo&quot;&gt;#&lt;/a&gt;
El comienzo&lt;/h2&gt;
&lt;p&gt;Primer commit a las 3:22. El prompt de misión imponía dos reglas: hacer una copia de seguridad de los 16 MB de flash originales antes de cualquier escritura, y no tocar nunca los eFuses ni la tensión del núcleo.&lt;/p&gt;
&lt;p&gt;La copia de seguridad estuvo a punto de fallar. A 921 600 baudios, el puerto USB desapareció en plena lectura. El agente volvió a empezar a 230 400 baudios, en bloques de 1 MB verificados uno a uno, porque por encima el cable introducía errores. A las 3:46, la copia completa estaba verificada y su hash SHA-256 registrado. A las 3:48, primer flasheo verificado en el reloj.&lt;/p&gt;
&lt;p&gt;Tuve un poco de miedo de brickear el reloj. No sabía de dónde venía el fallo; probablemente del cable. El agente se encargó de todo, hasta probar un flasheo lento y fraccionado para lidiar con ese cable defectuoso (!). Sus preguntas y sus métodos eran pertinentes y precisos, y eso era lo que me daba confianza.&lt;/p&gt;
&lt;p&gt;A las 4:09, la esfera de aviador aparecía en pantalla, con un segundero a 8 Hz.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/ressusciter-kronograf/kronograf-t1-aviator.webp&quot; alt=&quot;La esfera de cronógrafo de aviación, captura del reloj real por el puerto serie: bisel graduado, tres subesferas de batería, minutos y pasos, segundero naranja&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;La esfera de aviador, capturada en el reloj real por el puerto serie. Captura ya publicada en la entrada anterior.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;el-momento-en-que-se-rompio&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#el-momento-en-que-se-rompio&quot; aria-label=&quot;Anchor link for: el-momento-en-que-se-rompio&quot;&gt;#&lt;/a&gt;
El momento en que se rompió&lt;/h2&gt;
&lt;p&gt;Conectado por USB, el reloj aguantaba. Con batería, se colgaba sistemáticamente al cabo de unos segundos. Durante la mañana, temía que estuviera brickeado, y le metía prisa al agente para que fuera rápido antes del siguiente cuelgue. Tuve que apagarlo y encenderlo tres veces.&lt;/p&gt;
&lt;p&gt;Había dos causas, encontradas una tras otra. Primero, el watchdog del procesador seguía armado durante el sueño ligero. Ahora se suspende antes de entrar en reposo y se rearma al despertar. Después, una pulsación del botón congelaba el reloj. La línea de interrupción del chip de alimentación se queda en nivel bajo mientras no se lee, y la interrupción se volvía a disparar sin fin. Las interrupciones GPIO ahora se desactivan durante el sueño, y comprobé que el reloj aguantaba muy bien.&lt;/p&gt;
&lt;h2 id=&quot;una-decision-dejar-de-depender-del-cable&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#una-decision-dejar-de-depender-del-cable&quot; aria-label=&quot;Anchor link for: una-decision-dejar-de-depender-del-cable&quot;&gt;#&lt;/a&gt;
Una decisión: dejar de depender del cable&lt;/h2&gt;
&lt;p&gt;Los cortes del USB volvían durante los flasheos. Había dos opciones: esperar a que volviera el puerto, o hacer que el cable fuera accesorio. El agente propuso el «modo taller»: cuando el reloj está alimentado por USB y el Wi-Fi está configurado, se queda conectado, acepta actualizaciones por Wi-Fi (OTA) y expone una consola TCP. Un Wi-Fi encendido todo el tiempo es normalmente un antipatrón. Enchufado a la corriente, la batería no está en juego, y la opción se puede desactivar.&lt;/p&gt;
&lt;p&gt;Como el cable fallaba, el agente pasó por su cuenta a las actualizaciones por Wi-Fi (OTA). ¡Magia! Más tarde, los cortes aparecieron también mientras el procesador estaba en su cargador de arranque en ROM: así que el problema es de hardware, no de software. Después llegó un modo seguro: tras tres cuelgues seguidos en el primer minuto, el Bluetooth no arranca, para poder reparar siempre el reloj a distancia.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/ressusciter-kronograf/kronograf-photo.webp&quot; alt=&quot;El T-Watch 2020 real sobre la mesa: pantalla de diagnóstico de Kronograf, memoria, sensores detectados en verde, batería al 100 %&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;El reloj real en la pantalla de diagnóstico, la primera pantalla flasheada. Foto ya publicada en la entrada anterior.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;donde-estoy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#donde-estoy&quot; aria-label=&quot;Anchor link for: donde-estoy&quot;&gt;#&lt;/a&gt;
Dónde estoy&lt;/h2&gt;
&lt;p&gt;El problema del cable (B2 en &lt;code&gt;BLOCKERS.md&lt;/code&gt;) sigue abierto: la conexión micro-USB sigue siendo frágil. El doble toque que despierta la pantalla sigue siendo algo aleatorio, pero funciona. El gesto de muñeca para despertar el reloj todavía hay que ajustarlo. La autonomía durante un día entero aún no se ha medido.&lt;/p&gt;
&lt;p&gt;Lo que más me impresionó fue la rapidez con la que el agente flasheó el reloj por su cuenta y me mostró resultados concretos. Tengo muchas ganas de probarlo en otros aparatos. De hecho, pronto voy a volver a sacar mis micro:bits: ¡tengo una idea de proyecto!&lt;/p&gt;
&lt;aside class=&quot;transparence&quot; aria-label=&quot;Cómo se escribió esta entrada&quot;&gt;
  &lt;p class=&quot;transparence-titre&quot;&gt;Cómo se escribió esta entrada&lt;/p&gt;
  &lt;p&gt;Redactada por Claude Opus 5.5 a partir de: un encargo y una entrevista escritos por François, sus mensajes de sesión, el repositorio &lt;code&gt;kronograf&lt;/code&gt;, &lt;code&gt;DECISIONS.md&lt;/code&gt; y &lt;code&gt;BLOCKERS.md&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;Revisada y corregida por François en 30 min, 17 % del texto reescrito.&lt;/p&gt;
  &lt;p&gt;Traducida del francés por la IA, a partir de la versión revisada. La traducción no se revisó línea por línea.&lt;/p&gt;
&lt;/aside&gt;
</content>
    </entry>
    <entry xml:lang="es">
        <title>Doce minutos entre la idea y la tele</title>
        <published>2026-10-12T00:00:00+00:00</published>
        <updated>2026-10-12T00:00:00+00:00</updated>
        <author><name>François</name></author>
        <link rel="alternate" type="text/html" href="https://blok.storagebits.workers.dev/es/blog/quatre-jours/"/>
        <id>https://blok.storagebits.workers.dev/es/blog/quatre-jours/</id>
        <summary type="html">Cuatro días, seis proyectos, 159 commits. El tiempo entre «me gustaría» y «funciona en el aparato» se ha vuelto ridículo. Lo que aún frena soy yo, mis cables y mis cuotas.</summary>
        <content type="html" xml:base="https://blok.storagebits.workers.dev/es/blog/quatre-jours/">&lt;p&gt;Jueves 8 de octubre, 20:34. Envío un prompt de misión a un agente. A las 20:46, la hora aparece en grande en mi tele, con una tipografía que eligió el agente.&lt;/p&gt;
&lt;p&gt;Cuatro días después: seis proyectos, 159 commits, unos 240 mensajes míos, buena parte de menos de cinco palabras. «go T8». «vas-y présente la tranche 3» [venga, enséñame el tramo 3]. «c’est fait, reteste» [hecho, prueba otra vez].&lt;/p&gt;
&lt;p&gt;El tiempo entre la intención y lo concreto se ha vuelto ridículo. Doce minutos para la aplicación Almanak. Dieciséis para Lukarne. El cuello de botella ahora soy yo: mi sueño, mis cables, mis cuotas.&lt;/p&gt;
&lt;figure class=&quot;frise&quot;&gt;&lt;div class=&quot;defile&quot; tabindex=&quot;0&quot; role=&quot;region&quot; aria-label=&quot;Cronología, se desplaza horizontalmente&quot;&gt;&lt;svg viewBox=&quot;0 0 900 412&quot; role=&quot;img&quot; aria-labelledby=&quot;frise-titre frise-desc&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;title id=&quot;frise-titre&quot;&gt;Cuatro días de commits, proyecto por proyecto&lt;/title&gt;&lt;desc id=&quot;frise-desc&quot;&gt;Una fila por proyecto, del jueves 8 de octubre a las 19 h al lunes 12 a las 19 h. Cada trazo es un commit. El círculo vacío marca el primer mensaje al agente; el lleno, por encima de la fila, el primer resultado concreto. Las noches están sombreadas.&lt;/desc&gt;&lt;rect class=&quot;nuit&quot; x=&quot;157.3&quot; y=&quot;34&quot; width=&quot;55.0&quot; height=&quot;338&quot;/&gt;&lt;line class=&quot;grille&quot; x1=&quot;157.3&quot; x2=&quot;157.3&quot; y1=&quot;34&quot; y2=&quot;372&quot;/&gt;&lt;text class=&quot;axe&quot; x=&quot;161.3&quot; y=&quot;28&quot;&gt;vie. 9&lt;/text&gt;&lt;rect class=&quot;nuit&quot; x=&quot;345.8&quot; y=&quot;34&quot; width=&quot;55.0&quot; height=&quot;338&quot;/&gt;&lt;line class=&quot;grille&quot; x1=&quot;345.8&quot; x2=&quot;345.8&quot; y1=&quot;34&quot; y2=&quot;372&quot;/&gt;&lt;text class=&quot;axe&quot; x=&quot;349.8&quot; y=&quot;28&quot;&gt;sáb. 10&lt;/text&gt;&lt;rect class=&quot;nuit&quot; x=&quot;534.3&quot; y=&quot;34&quot; width=&quot;55.0&quot; height=&quot;338&quot;/&gt;&lt;line class=&quot;grille&quot; x1=&quot;534.3&quot; x2=&quot;534.3&quot; y1=&quot;34&quot; y2=&quot;372&quot;/&gt;&lt;text class=&quot;axe&quot; x=&quot;538.3&quot; y=&quot;28&quot;&gt;dom. 11&lt;/text&gt;&lt;rect class=&quot;nuit&quot; x=&quot;722.8&quot; y=&quot;34&quot; width=&quot;55.0&quot; height=&quot;338&quot;/&gt;&lt;line class=&quot;grille&quot; x1=&quot;722.8&quot; x2=&quot;722.8&quot; y1=&quot;34&quot; y2=&quot;372&quot;/&gt;&lt;text class=&quot;axe&quot; x=&quot;726.8&quot; y=&quot;28&quot;&gt;lun. 12&lt;/text&gt;&lt;text class=&quot;axe&quot; x=&quot;118.0&quot; y=&quot;28&quot;&gt;jue. 8&lt;/text&gt;&lt;text class=&quot;nom&quot; x=&quot;104&quot; y=&quot;85.0&quot; text-anchor=&quot;end&quot;&gt;Almanak&lt;/text&gt;&lt;line class=&quot;rail&quot; x1=&quot;118&quot; x2=&quot;872&quot; y1=&quot;81.0&quot; y2=&quot;81.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;669.9&quot; x2=&quot;669.9&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;669.6&quot; x2=&quot;669.6&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;611.3&quot; x2=&quot;611.3&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;145.9&quot; x2=&quot;145.9&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;145.3&quot; x2=&quot;145.3&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;140.8&quot; x2=&quot;140.8&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;139.4&quot; x2=&quot;139.4&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;137.5&quot; x2=&quot;137.5&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;135.9&quot; x2=&quot;135.9&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;133.6&quot; x2=&quot;133.6&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;131.9&quot; x2=&quot;131.9&quot; y1=&quot;74.0&quot; y2=&quot;88.0&quot;/&gt;&lt;path class=&quot;delai&quot; d=&quot;M130.3,81.0 L131.9,81.0 L131.9,63.0&quot;/&gt;&lt;circle class=&quot;intention&quot; cx=&quot;130.3&quot; cy=&quot;81.0&quot; r=&quot;5&quot;&gt;&lt;title&gt;jue. 20:34 · prompt de misión&lt;/title&gt;&lt;/circle&gt;&lt;circle class=&quot;concret&quot; cx=&quot;131.9&quot; cy=&quot;63.0&quot; r=&quot;5.5&quot;&gt;&lt;title&gt;20:46 · la hora aparece en la tele&lt;/title&gt;&lt;/circle&gt;&lt;text class=&quot;etiquette&quot; x=&quot;140.9&quot; y=&quot;67.0&quot;&gt;12 min&lt;/text&gt;&lt;text class=&quot;compte&quot; x=&quot;880&quot; y=&quot;85.0&quot;&gt;11&lt;/text&gt;&lt;text class=&quot;nom&quot; x=&quot;104&quot; y=&quot;139.0&quot; text-anchor=&quot;end&quot;&gt;Homelab&lt;/text&gt;&lt;line class=&quot;rail&quot; x1=&quot;118&quot; x2=&quot;872&quot; y1=&quot;135.0&quot; y2=&quot;135.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;869.9&quot; x2=&quot;869.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;863.8&quot; x2=&quot;863.8&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;863.3&quot; x2=&quot;863.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;859.6&quot; x2=&quot;859.6&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;847.3&quot; x2=&quot;847.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;843.9&quot; x2=&quot;843.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;838.3&quot; x2=&quot;838.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;820.5&quot; x2=&quot;820.5&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;819.9&quot; x2=&quot;819.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;819.9&quot; x2=&quot;819.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;811.7&quot; x2=&quot;811.7&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;810.2&quot; x2=&quot;810.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;807.8&quot; x2=&quot;807.8&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;777.1&quot; x2=&quot;777.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;762.2&quot; x2=&quot;762.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;757.2&quot; x2=&quot;757.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;755.4&quot; x2=&quot;755.4&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;752.5&quot; x2=&quot;752.5&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;747.7&quot; x2=&quot;747.7&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;729.7&quot; x2=&quot;729.7&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;729.1&quot; x2=&quot;729.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;715.3&quot; x2=&quot;715.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;707.6&quot; x2=&quot;707.6&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;706.1&quot; x2=&quot;706.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;704.2&quot; x2=&quot;704.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;703.4&quot; x2=&quot;703.4&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;697.9&quot; x2=&quot;697.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;693.0&quot; x2=&quot;693.0&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;692.3&quot; x2=&quot;692.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;690.6&quot; x2=&quot;690.6&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;688.3&quot; x2=&quot;688.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;675.3&quot; x2=&quot;675.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;672.7&quot; x2=&quot;672.7&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;670.4&quot; x2=&quot;670.4&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;666.2&quot; x2=&quot;666.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;665.0&quot; x2=&quot;665.0&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;663.7&quot; x2=&quot;663.7&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;663.4&quot; x2=&quot;663.4&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;661.3&quot; x2=&quot;661.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;660.2&quot; x2=&quot;660.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;656.5&quot; x2=&quot;656.5&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;651.3&quot; x2=&quot;651.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;640.9&quot; x2=&quot;640.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;639.3&quot; x2=&quot;639.3&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;627.0&quot; x2=&quot;627.0&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;624.1&quot; x2=&quot;624.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;617.1&quot; x2=&quot;617.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;615.1&quot; x2=&quot;615.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;579.8&quot; x2=&quot;579.8&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;532.9&quot; x2=&quot;532.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;532.8&quot; x2=&quot;532.8&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;527.1&quot; x2=&quot;527.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;526.5&quot; x2=&quot;526.5&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;526.0&quot; x2=&quot;526.0&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;496.1&quot; x2=&quot;496.1&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;495.7&quot; x2=&quot;495.7&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;494.8&quot; x2=&quot;494.8&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;488.8&quot; x2=&quot;488.8&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;488.2&quot; x2=&quot;488.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;487.9&quot; x2=&quot;487.9&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;484.2&quot; x2=&quot;484.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;484.2&quot; x2=&quot;484.2&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;478.5&quot; x2=&quot;478.5&quot; y1=&quot;128.0&quot; y2=&quot;142.0&quot;/&gt;&lt;path class=&quot;delai&quot; d=&quot;M136.2,135.0 L141.6,135.0 L141.6,117.0&quot;/&gt;&lt;circle class=&quot;intention&quot; cx=&quot;136.2&quot; cy=&quot;135.0&quot; r=&quot;5&quot;&gt;&lt;title&gt;jue. 21:19 · «¡vamos!»&lt;/title&gt;&lt;/circle&gt;&lt;circle class=&quot;concret&quot; cx=&quot;141.6&quot; cy=&quot;117.0&quot; r=&quot;5.5&quot;&gt;&lt;title&gt;22:00 · doble autenticación activa en la pasarela&lt;/title&gt;&lt;/circle&gt;&lt;text class=&quot;etiquette&quot; x=&quot;150.6&quot; y=&quot;121.0&quot;&gt;41 min&lt;/text&gt;&lt;text class=&quot;compte&quot; x=&quot;880&quot; y=&quot;139.0&quot;&gt;63&lt;/text&gt;&lt;text class=&quot;nom&quot; x=&quot;104&quot; y=&quot;193.0&quot; text-anchor=&quot;end&quot;&gt;Lukarne&lt;/text&gt;&lt;line class=&quot;rail&quot; x1=&quot;118&quot; x2=&quot;872&quot; y1=&quot;189.0&quot; y2=&quot;189.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;852.5&quot; x2=&quot;852.5&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;842.4&quot; x2=&quot;842.4&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;812.1&quot; x2=&quot;812.1&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;743.0&quot; x2=&quot;743.0&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;730.6&quot; x2=&quot;730.6&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;729.1&quot; x2=&quot;729.1&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;726.2&quot; x2=&quot;726.2&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;724.3&quot; x2=&quot;724.3&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;708.1&quot; x2=&quot;708.1&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;705.9&quot; x2=&quot;705.9&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;705.3&quot; x2=&quot;705.3&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;703.9&quot; x2=&quot;703.9&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;656.5&quot; x2=&quot;656.5&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;655.3&quot; x2=&quot;655.3&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;652.0&quot; x2=&quot;652.0&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;650.7&quot; x2=&quot;650.7&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;643.4&quot; x2=&quot;643.4&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;642.9&quot; x2=&quot;642.9&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;610.2&quot; x2=&quot;610.2&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;531.0&quot; x2=&quot;531.0&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;429.2&quot; x2=&quot;429.2&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;321.5&quot; x2=&quot;321.5&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;317.3&quot; x2=&quot;317.3&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;312.5&quot; x2=&quot;312.5&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;307.7&quot; x2=&quot;307.7&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;306.0&quot; x2=&quot;306.0&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;300.5&quot; x2=&quot;300.5&quot; y1=&quot;182.0&quot; y2=&quot;196.0&quot;/&gt;&lt;path class=&quot;delai&quot; d=&quot;M298.4,189.0 L300.5,189.0 L300.5,171.0&quot;/&gt;&lt;circle class=&quot;intention&quot; cx=&quot;298.4&quot; cy=&quot;189.0&quot; r=&quot;5&quot;&gt;&lt;title&gt;vie. 17:58 · prompt de misión&lt;/title&gt;&lt;/circle&gt;&lt;circle class=&quot;concret&quot; cx=&quot;300.5&quot; cy=&quot;171.0&quot; r=&quot;5.5&quot;&gt;&lt;title&gt;18:14 · primera webcam en directo a pantalla completa&lt;/title&gt;&lt;/circle&gt;&lt;text class=&quot;etiquette&quot; x=&quot;309.5&quot; y=&quot;175.0&quot;&gt;16 min&lt;/text&gt;&lt;text class=&quot;compte&quot; x=&quot;880&quot; y=&quot;193.0&quot;&gt;27&lt;/text&gt;&lt;text class=&quot;nom&quot; x=&quot;104&quot; y=&quot;247.0&quot; text-anchor=&quot;end&quot;&gt;DropboksTV&lt;/text&gt;&lt;line class=&quot;rail&quot; x1=&quot;118&quot; x2=&quot;872&quot; y1=&quot;243.0&quot; y2=&quot;243.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;687.6&quot; x2=&quot;687.6&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;683.4&quot; x2=&quot;683.4&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;682.4&quot; x2=&quot;682.4&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;679.4&quot; x2=&quot;679.4&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;679.4&quot; x2=&quot;679.4&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;677.5&quot; x2=&quot;677.5&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;676.7&quot; x2=&quot;676.7&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;673.1&quot; x2=&quot;673.1&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;668.8&quot; x2=&quot;668.8&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;666.6&quot; x2=&quot;666.6&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;663.3&quot; x2=&quot;663.3&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;660.2&quot; x2=&quot;660.2&quot; y1=&quot;236.0&quot; y2=&quot;250.0&quot;/&gt;&lt;path class=&quot;delai&quot; d=&quot;M654.4,243.0 L660.2,243.0 L660.2,225.0&quot;/&gt;&lt;circle class=&quot;intention&quot; cx=&quot;654.4&quot; cy=&quot;243.0&quot; r=&quot;5&quot;&gt;&lt;title&gt;dom. 15:18 · «lee el prompt y adelante»&lt;/title&gt;&lt;/circle&gt;&lt;circle class=&quot;concret&quot; cx=&quot;660.2&quot; cy=&quot;225.0&quot; r=&quot;5.5&quot;&gt;&lt;title&gt;16:02 · emparejamiento logrado en la tele&lt;/title&gt;&lt;/circle&gt;&lt;text class=&quot;etiquette&quot; x=&quot;669.2&quot; y=&quot;229.0&quot;&gt;44 min&lt;/text&gt;&lt;text class=&quot;compte&quot; x=&quot;880&quot; y=&quot;247.0&quot;&gt;12&lt;/text&gt;&lt;text class=&quot;nom&quot; x=&quot;104&quot; y=&quot;301.0&quot; text-anchor=&quot;end&quot;&gt;shot2cart&lt;/text&gt;&lt;line class=&quot;rail&quot; x1=&quot;118&quot; x2=&quot;872&quot; y1=&quot;297.0&quot; y2=&quot;297.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;775.5&quot; x2=&quot;775.5&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;770.9&quot; x2=&quot;770.9&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;768.6&quot; x2=&quot;768.6&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;767.6&quot; x2=&quot;767.6&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;760.8&quot; x2=&quot;760.8&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;754.5&quot; x2=&quot;754.5&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;751.4&quot; x2=&quot;751.4&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;745.4&quot; x2=&quot;745.4&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;731.1&quot; x2=&quot;731.1&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;718.0&quot; x2=&quot;718.0&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;716.9&quot; x2=&quot;716.9&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;715.1&quot; x2=&quot;715.1&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;694.1&quot; x2=&quot;694.1&quot; y1=&quot;290.0&quot; y2=&quot;304.0&quot;/&gt;&lt;path class=&quot;delai&quot; d=&quot;M693.1,297.0 L715.0,297.0 L715.0,279.0&quot;/&gt;&lt;circle class=&quot;intention&quot; cx=&quot;693.1&quot; cy=&quot;297.0&quot; r=&quot;5&quot;&gt;&lt;title&gt;dom. 20:13 · «forget about previous session»&lt;/title&gt;&lt;/circle&gt;&lt;circle class=&quot;concret&quot; cx=&quot;715.0&quot; cy=&quot;279.0&quot; r=&quot;5.5&quot;&gt;&lt;title&gt;23:01 · foto → lista → enlaces de tienda&lt;/title&gt;&lt;/circle&gt;&lt;text class=&quot;etiquette&quot; x=&quot;724.0&quot; y=&quot;283.0&quot;&gt;2 h 48&lt;/text&gt;&lt;text class=&quot;compte&quot; x=&quot;880&quot; y=&quot;301.0&quot;&gt;13&lt;/text&gt;&lt;text class=&quot;nom&quot; x=&quot;104&quot; y=&quot;355.0&quot; text-anchor=&quot;end&quot;&gt;Kronograf&lt;/text&gt;&lt;line class=&quot;rail&quot; x1=&quot;118&quot; x2=&quot;872&quot; y1=&quot;351.0&quot; y2=&quot;351.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;861.6&quot; x2=&quot;861.6&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;845.9&quot; x2=&quot;845.9&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;844.8&quot; x2=&quot;844.8&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;843.7&quot; x2=&quot;843.7&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;839.5&quot; x2=&quot;839.5&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;823.0&quot; x2=&quot;823.0&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;820.9&quot; x2=&quot;820.9&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;817.6&quot; x2=&quot;817.6&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;813.3&quot; x2=&quot;813.3&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;811.5&quot; x2=&quot;811.5&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;810.9&quot; x2=&quot;810.9&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;809.4&quot; x2=&quot;809.4&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;802.1&quot; x2=&quot;802.1&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;776.0&quot; x2=&quot;776.0&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;775.4&quot; x2=&quot;775.4&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;767.6&quot; x2=&quot;767.6&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;761.5&quot; x2=&quot;761.5&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;760.7&quot; x2=&quot;760.7&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;759.9&quot; x2=&quot;759.9&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;759.1&quot; x2=&quot;759.1&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;756.9&quot; x2=&quot;756.9&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;756.8&quot; x2=&quot;756.8&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;756.2&quot; x2=&quot;756.2&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;756.0&quot; x2=&quot;756.0&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;755.5&quot; x2=&quot;755.5&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;754.2&quot; x2=&quot;754.2&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;754.1&quot; x2=&quot;754.1&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;752.7&quot; x2=&quot;752.7&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;752.4&quot; x2=&quot;752.4&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;752.1&quot; x2=&quot;752.1&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;751.5&quot; x2=&quot;751.5&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;749.9&quot; x2=&quot;749.9&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;line class=&quot;commit&quot; x1=&quot;749.3&quot; x2=&quot;749.3&quot; y1=&quot;344.0&quot; y2=&quot;358.0&quot;/&gt;&lt;path class=&quot;delai&quot; d=&quot;M748.8,351.0 L752.6,351.0 L752.6,333.0&quot;/&gt;&lt;circle class=&quot;intention&quot; cx=&quot;748.8&quot; cy=&quot;351.0&quot; r=&quot;5&quot;&gt;&lt;title&gt;lun. 3:19 · «read it and get started»&lt;/title&gt;&lt;/circle&gt;&lt;circle class=&quot;concret&quot; cx=&quot;752.6&quot; cy=&quot;333.0&quot; r=&quot;5.5&quot;&gt;&lt;title&gt;3:48 · primer flasheo verificado en el reloj&lt;/title&gt;&lt;/circle&gt;&lt;text class=&quot;etiquette&quot; x=&quot;761.6&quot; y=&quot;337.0&quot;&gt;29 min&lt;/text&gt;&lt;text class=&quot;compte&quot; x=&quot;880&quot; y=&quot;355.0&quot;&gt;33&lt;/text&gt;&lt;g class=&quot;legende&quot; transform=&quot;translate(118,394)&quot;&gt;&lt;circle class=&quot;intention&quot; cx=&quot;6&quot; cy=&quot;0&quot; r=&quot;5&quot;/&gt;&lt;text x=&quot;16&quot; y=&quot;4&quot;&gt;primer mensaje al agente&lt;/text&gt;&lt;circle class=&quot;concret&quot; cx=&quot;236&quot; cy=&quot;0&quot; r=&quot;5.5&quot;/&gt;&lt;text x=&quot;246&quot; y=&quot;4&quot;&gt;primer resultado concreto&lt;/text&gt;&lt;line class=&quot;commit&quot; x1=&quot;452&quot; x2=&quot;452&quot; y1=&quot;-7&quot; y2=&quot;7&quot;/&gt;&lt;text x=&quot;462&quot; y=&quot;4&quot;&gt;un commit&lt;/text&gt;&lt;rect class=&quot;nuit&quot; x=&quot;560&quot; y=&quot;-7&quot; width=&quot;14&quot; height=&quot;14&quot;/&gt;&lt;text x=&quot;580&quot; y=&quot;4&quot;&gt;noche&lt;/text&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/div&gt;&lt;figcaption&gt;Una fila por proyecto, del jueves a las 19 h al lunes a las 19 h. La cifra de la derecha cuenta los commits. Pasa el cursor por los círculos para ver las horas exactas.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Cada fila es un proyecto, cada trazo un commit. El círculo vacío es mi primer mensaje al agente. El lleno, por encima de la fila, es lo primero concreto: la app funcionando en la tele, el firmware en el reloj, la doble autenticación activa en la pasarela del homelab. Las bandas grises son las noches. Hay commits dentro. No siempre porque yo estuviera despierto.&lt;/p&gt;
&lt;h2 id=&quot;jueves-por-la-noche-tres-agentes-en-45-minutos&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#jueves-por-la-noche-tres-agentes-en-45-minutos&quot; aria-label=&quot;Anchor link for: jueves-por-la-noche-tres-agentes-en-45-minutos&quot;&gt;#&lt;/a&gt;
Jueves por la noche: tres agentes en 45 minutos&lt;/h2&gt;
&lt;p&gt;La noche del 8, en 45 minutos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;20:34: sale la misión Almanak.&lt;/li&gt;
&lt;li&gt;20:36: retomo shot2cart, un proyecto empezado en septiembre con otra herramienta. «inspect project, it comes from an other AI conversation, inspect and we pursue».&lt;/li&gt;
&lt;li&gt;21:07: descargo desde claude.ai el &lt;code&gt;CLAUDE.md&lt;/code&gt; de mi homelab, que estoy rediseñando con un LLM. Lo acababa de escribir con otra instancia mientras la primera construía Almanak.&lt;/li&gt;
&lt;li&gt;21:19: «je viens de créer CLAUDE.md pour toi, c’est parti !» [acabo de crear CLAUDE.md para ti, ¡vamos!]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nadie espera a nadie. Mientras un agente compila, escribo la misión del siguiente con un tercero.&lt;/p&gt;
&lt;h2 id=&quot;almanak-la-chispa&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#almanak-la-chispa&quot; aria-label=&quot;Anchor link for: almanak-la-chispa&quot;&gt;#&lt;/a&gt;
Almanak, la chispa&lt;/h2&gt;
&lt;p&gt;El north star cabía en una frase:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Una pantalla que apetece dejar encendida. Cuando paso por delante de mi tele, sé en 2 segundos la hora, la fecha, el tiempo que hace y que va a hacer, y en cuántos minutos pasa mi próximo autobús. Es bonita como un objeto de diseño, no como un panel de administración.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Y una regla que mantuve en todos los proyectos siguientes: ningún tramo está terminado hasta que el agente lo ha visto funcionar en la Shield. Hace una captura por adb, la lee, la critica. Legibilidad a 3 m, overscan, desbordes. Y para cada tramo visual, dos variantes; nos quedamos con la mejor.&lt;/p&gt;
&lt;div class=&quot;galerie&quot;&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/almanak.webp&quot; alt=&quot;Almanak en la tele, tema oscuro: la hora en grande, la fecha, el día del año, los próximos autobuses y el tiempo a cinco días&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/almanak-papier.webp&quot; alt=&quot;Almanak, tema papel: la hora, el santo del día, los autobuses y la curva de temperatura de las próximas horas&quot; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Almanak en la Shield la primera noche: el tema oscuro a las 22:17, el tema papel a las 21:38.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Siete tramos entre las 20:46 y las 22:32. Para el reloj, el agente comparó una serif editorial con una sans-serif suiza y se quedó con Fraunces, porque a 3 m, Inter con grosor 200 «empieza a parecer un alambre». Tiene razón.&lt;/p&gt;
&lt;p&gt;El mejor bug: la sincronización de horarios de autobús devolvía &lt;code&gt;HTTP 441&lt;/code&gt; en la Shield y funcionaba desde el Mac. El agente rebuscó en &lt;code&gt;dumpsys connectivity&lt;/code&gt; y encontró la VPN que corre en la Shield: la web de la STM (la red de transporte de Montreal) rechaza las IP de salida de las VPN. Pasó a un espejo del mismo flujo, byte a byte, y documentó el split tunneling en el README. El prompt no decía nada de una VPN.&lt;/p&gt;
&lt;p&gt;Para ser honesto: mi definición de «terminado» pedía 24 horas de salvapantallas sin fuga de memoria. La medida real cubre más o menos una hora. Terminado, pues. Entre comillas.&lt;/p&gt;
&lt;h2 id=&quot;lukarne-mi-favorito&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lukarne-mi-favorito&quot; aria-label=&quot;Anchor link for: lukarne-mi-favorito&quot;&gt;#&lt;/a&gt;
Lukarne, mi favorito&lt;/h2&gt;
&lt;p&gt;Al día siguiente, 17:58, segunda misión. Una ventana al mundo: girar un globo con el mando, lanzarse sobre una región, ver un mosaico de webcams en directo, saltar de una cámara a otra. La frase que cuenta en el prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Si una interacción no es fluida con el mando, ha fracasado, aunque sea técnicamente correcta.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Y otra, más discreta, que explica por qué todo fue tan rápido: «Ya desarrollé otra app de Google TV contigo en esta misma Shield. Antes de nada, busca en mi entorno […] cómo nos conectamos […]. Reutiliza lo que funciona.» Cada proyecto deja tras de sí una dirección adb, un script de despliegue, un formato de &lt;code&gt;DECISIONS.md&lt;/code&gt;. El siguiente arranca desde ahí.&lt;/p&gt;
&lt;p&gt;18:14: primer directo a pantalla completa en la tele, HLS y YouTube, izquierda/derecha para pasar de uno a otro. 16 minutos. A las 20:54, la V1 estaba lista: un globo día/noche en OpenGL a 60 imágenes por segundo (3 ms por imagen), 1640 cámaras en 34 regiones (19 más desde el lunes), un mosaico 3×3 cuya casilla seleccionada pasa a directo en dos segundos, y un botón «sorpréndeme» que te manda adonde es de día. Dos pruebas de resistencia de 22 minutos, cero cuelgues.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/lukarne-globe.webp&quot; alt=&quot;El globo de Lukarne centrado en Europa de noche, Venecia seleccionada, una webcam de la cuenca de San Marcos en una esquina&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lukarne: Europa de noche, Venecia seleccionada, 16 webcams en directo, la cuenca de San Marcos en la esquina.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Lo más fácil es verla funcionar:&lt;/p&gt;
&lt;figure class=&quot;video&quot;&gt;&lt;video controls muted playsinline preload=&quot;metadata&quot; poster=&quot;lukarne-visite-poster.jpg&quot;&gt;&lt;source src=&quot;lukarne-visite.mp4&quot; type=&quot;video/mp4&quot;&gt;&lt;/video&gt;&lt;figcaption&gt;78 segundos en la Shield, sin sonido: el globo hasta California, la zambullida en Pollock Pines, el mosaico de cámaras de autopista en directo, la pantalla completa, la cámara siguiente, la subida, y luego «surprise me».&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Este vídeo lo grabó el agente, el lunes por la noche, para esta entrada. Manejaba la Shield con un mando virtual (&lt;code&gt;adb shell input keyevent&lt;/code&gt;) y grababa la pantalla con &lt;code&gt;screenrecord&lt;/code&gt;. La primera toma fue en francés, sobre Europa, donde era la 1 de la madrugada: todo estaba negro. Repitió la toma en inglés, sobre California, de día.&lt;/p&gt;
&lt;div class=&quot;galerie&quot;&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/lukarne-mosaique.webp&quot; alt=&quot;El mosaico de Pollock Pines: nueve cámaras de la autopista US 50 en directo, la casilla seleccionada recuadrada&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/lukarne-plein-ecran.webp&quot; alt=&quot;Pantalla completa de una cámara de autopista en California, un coche rojo en el cruce, el nombre del lugar y la hora local abajo&quot; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;El mosaico de un lugar y luego la pantalla completa. Izquierda/derecha salta a la cámara vecina sin volver al mosaico.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/lukarne-aurore.webp&quot; alt=&quot;Una aurora boreal verde sobre Fairbanks, Alaska, con el nombre de la cámara y la hora local&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;«surprise me» cayó aquí, en pleno rodaje. La cámara de auroras de explore.org en Fairbanks, 15:09 hora local: seguramente una reposición de la noche entre dos planos en directo.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Luego la usé, y me quejé. Sábado, 23:20: «je suis assez surpris du peu de flux video , bcp d’images fixes qui apportent peu» [me sorprende lo poco que hay en vídeo, muchas imágenes fijas que aportan poco]. 23:34, commit: primero el directo, las imágenes fijas como opción. Catorce minutos.&lt;/p&gt;
&lt;p&gt;En la noche del domingo al lunes, a las 00:08: «parfait , je vais dormir là» [perfecto, me voy a dormir]. Y dos peticiones: «les vignettes pixelisée : on peut trouver un moyen de charger ne serait ce qu 1 frame propre plutôt que la vignette degeueu ?» [las miniaturas pixeladas: ¿podemos cargar aunque sea 1 fotograma limpio en vez de esa miniatura asquerosa?], y para el último nivel de zoom, un «effet plongeant genre zoom google earth» [efecto de zambullida tipo zoom de Google Earth]. A las 00:26, las miniaturas son fotogramas reales capturados en el aparato durante la reproducción. A las 00:48, te lanzas sobre un lugar con un zoom ×30, se encienden las luces, y vuelves a subir. A las 00:59, prueba de resistencia de 10 minutos después de todo eso. Yo dormía.&lt;/p&gt;
&lt;p&gt;El lunes por la tarde pedí un modo demo, para que la tele viaje sola. 41 minutos después:&lt;/p&gt;
&lt;figure class=&quot;video&quot;&gt;&lt;video autoplay loop muted playsinline preload=&quot;metadata&quot; poster=&quot;lukarne-demo-poster.jpg&quot;&gt;&lt;source src=&quot;lukarne-demo.mp4&quot; type=&quot;video/mp4&quot;&gt;&lt;/video&gt;&lt;figcaption&gt;El modo demo: cámaras al azar donde es de día, nunca dos veces la misma región, con un fundido a un cartel entre una y otra.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/lukarne-reglages.webp&quot; alt=&quot;El panel de ajustes de Lukarne abierto sobre el globo: idioma, temperatura, imágenes fijas, reproductor en esquina, tiempo por cámara del modo demo, créditos de las fuentes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Los ajustes, a un botón del mando: idioma (inglés, francés, español), unidades, imágenes fijas o solo directo, reproductor en esquina, tiempo por cámara del modo demo y los créditos de cada fuente.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Lo que aún falta: la cobertura en directo fuera de Norteamérica es escasa. El primer día, el agente gastó toda la cuota de búsqueda de YouTube mientras dos bugs ocultaban los resultados. Ahora un repositorio público republica cada día el catálogo de directos, y la app lo descarga detrás de su logo. Y hay un bug que no siempre consigo reproducir: una webcam de YouTube que se queda congelada al encadenar dos. Lo señalé a las 15:46 y hubo un arreglo a las 16:31. Falta comprobarlo en la tele.&lt;/p&gt;
&lt;h2 id=&quot;dropbokstv-un-domingo-por-la-tarde&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#dropbokstv-un-domingo-por-la-tarde&quot; aria-label=&quot;Anchor link for: dropbokstv-un-domingo-por-la-tarde&quot;&gt;#&lt;/a&gt;
DropboksTV, un domingo por la tarde&lt;/h2&gt;
&lt;p&gt;Un cliente de Dropbox para la tele, pensado para el sofá: fotos y vídeos primero, solo lectura, sin backend. Domingo, 15:18: «read prompt-dropbokstv-claude-code.md and go». 16:02: el emparejamiento por teléfono funciona en la tele. 18:28: octavo y último tramo, con búsqueda, modo sin conexión, salvapantallas y 128 textos traducidos por idioma.&lt;/p&gt;
&lt;p&gt;Lo más retorcido es el emparejamiento. Conectarse a Dropbox desde una tele, sin teclado, debería ser un código que escribes en el teléfono. Solo que la API de Dropbox no ofrece ese flujo. El agente lo comprobó en el SDK y lo anotó en su registro de decisiones. Así que montó otra cosa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la tele muestra un código QR que apunta a una página servida por la propia tele, en el wifi de casa;&lt;/li&gt;
&lt;li&gt;el teléfono abre esa página, que lo manda a autorizar DropboksTV en Dropbox;&lt;/li&gt;
&lt;li&gt;Dropbox muestra un código, lo pegas en el teléfono, y la tele lo cambia por un token (PKCE: el secreto nunca sale de la tele, sin backend);&lt;/li&gt;
&lt;li&gt;la sesión caduca a los 10 minutos y la tele renueva el QR sola. Un error al teclear no quema la sesión. Y si el teléfono no ve la tele, un botón cambia al enlace directo de Dropbox.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;El pequeño servidor HTTP de la tele (150 líneas) lo sacó de Almanak.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/dropbokstv-appairage.webp&quot; alt=&quot;Pantalla de emparejamiento de DropboksTV: tres pasos numerados y un código QR, difuminado aquí&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;El emparejamiento&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Y luego está el visor. En tres tramos, entre las 16:25 y las 18:07, el agente escribió un visor que abre prácticamente todo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;las fotos, con zoom ×2 y ×3 que se desplaza con las flechas, y un pase de diapositivas con fundido o Ken Burns;&lt;/li&gt;
&lt;li&gt;los vídeos: H.264, HEVC hasta 4K, reanudación donde lo dejaste, subtítulos &lt;code&gt;.srt&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;los PDF, página a página, con zoom;&lt;/li&gt;
&lt;li&gt;Word y PowerPoint, que Dropbox convierte a PDF, y las hojas de cálculo, escaladas al 170 % para leerlas desde el sofá;&lt;/li&gt;
&lt;li&gt;el Markdown con formato, el código con números de línea y colores;&lt;/li&gt;
&lt;li&gt;la música, MP3 y FLAC, con la portada;&lt;/li&gt;
&lt;li&gt;y para todo lo demás, un código QR que manda el archivo al teléfono.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;El reproductor de vídeo llevó 16 minutos. Los documentos, la música y el envío al teléfono, 27. Una locura.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/dropbokstv-formats.webp&quot; alt=&quot;Ocho pantallas de DropboksTV: una foto ampliada, un vídeo, un PDF, una hoja de cálculo, notas en Markdown, código Kotlin, una canción con su portada y la pantalla de envío al teléfono&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;En orden: foto ampliada, vídeo, PDF, hoja de cálculo, Markdown, código, música, envío al teléfono (QR difuminado). Los archivos de prueba los fabricó el propio agente y los dejó en una carpeta de Dropbox dedicada. Capturas tomadas durante el desarrollo, en francés.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;kronograf-o-la-vuelta-del-hardware&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#kronograf-o-la-vuelta-del-hardware&quot; aria-label=&quot;Anchor link for: kronograf-o-la-vuelta-del-hardware&quot;&gt;#&lt;/a&gt;
Kronograf, o la vuelta del hardware&lt;/h2&gt;
&lt;p&gt;Lunes, 3:19 de la madrugada, un reloj LilyGO T-Watch de 2020 conectado por USB, y una misión: una esfera de cronógrafo de aviación y unos visores de 7 segmentos «circuitos temporales». A las 3:48, primer flasheo verificado en el reloj, después de una copia completa del flash original. Era la regla n.º 2 del prompt: no se escribe nada en el reloj sin red de seguridad. El cable falló durante la primera copia, y el agente se negó a flashear hasta tener una completa.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blok.storagebits.workers.dev/es/blog/quatre-jours/kronograf-photo.webp&quot; alt=&quot;El T-Watch 2020 real sobre la mesa: pantalla de diagnóstico de Kronograf, memoria, sensores detectados en verde, batería al 100 %&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;El reloj real, el lunes a las 18:11: la pantalla de diagnóstico, la primera que se flasheó. En verde, los chips detectados; en gris, lo que la V1 no tiene.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;duo&quot;&gt;&lt;img src=&quot;kronograf-t1-aviator.webp&quot; alt=&quot;Esfera de cronógrafo de aviación: bisel graduado, tres subesferas de batería, minutos y pasos, segundero naranja&quot;&gt;&lt;img class=&quot;carre&quot; src=&quot;kronograf-t2-face1.webp&quot; alt=&quot;Esfera con visores de 7 segmentos: destino en rojo, presente en verde, última sincronización en naranja&quot;&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;A la izquierda, captura del reloj real por el puerto serie. A la derecha, la esfera «circuitos temporales» en el simulador, que compila exactamente la misma interfaz.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Aquí el tiempo vuelve a subir, y no es culpa del agente. Ya no es código contra un emulador, es un conector micro-USB cansado. Mis mensajes de esa mañana: «elle plante systematiquement au bout de quelque secondes» [se cuelga siempre a los pocos segundos], «va vite sinon elle plante» [date prisa o se cuelga], «j’espère qu’elle n’est pas brikée» [espero que no se haya quedado brickeado]. El problema venía del sueño ligero, con una tormenta de interrupciones al despertar con el botón. A las 11:17: «ce semble tres bien tenir maintenant» [ahora parece aguantar muy bien]. A las 11:18: «go pour la météo» [adelante con el tiempo]. A las 11:31, el reloj muestra el tiempo y el próximo autobús en tiempo real.&lt;/p&gt;
&lt;p&gt;Esta noche tiene 33 commits, alarmas, cronómetro, podómetro, actualizaciones por wifi y las notificaciones del iPhone por Bluetooth, que todavía no enganchan bien. El doble toque es «un peu alétoire , comme le mouvement du poignet … mais ca passe» [algo aleatorio, como el gesto de muñeca… pero vale].&lt;/p&gt;
&lt;h2 id=&quot;el-homelab-y-la-app-shot2cart&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#el-homelab-y-la-app-shot2cart&quot; aria-label=&quot;Anchor link for: el-homelab-y-la-app-shot2cart&quot;&gt;#&lt;/a&gt;
El homelab, y la app shot2cart&lt;/h2&gt;
&lt;p&gt;La obra más larga no se ve. Sesenta commits y 276 mensajes para rehacer el servidor de casa: inventario, copias de seguridad con pruebas reales de restauración, acceso remoto con passkeys para la familia, alertas, una página de inicio con un esquema animado de la infraestructura y otro de la red local.&lt;/p&gt;
&lt;p&gt;Mi mensaje favorito de toda la serie, la primera noche: «ignore cet audit ; je ne compte que sur toi maintenant» [olvida esa auditoría; ahora solo cuento contigo]. El más sincero, el domingo: «Nest dans Home Assistant c’est payant ??!!» [¿¿Nest en Home Assistant es de pago??!!]. Pues sí, 5 $, gracias Google.&lt;/p&gt;
&lt;p&gt;shot2cart es el contraejemplo. La idea de la app: una foto de una lista de la compra, y el carrito se abre en la tienda en menos de 15 segundos, sin teclear nada. Primer intento en septiembre, con otra herramienta y un flujo basado en especificaciones: tres días, dos commits. El jueves por la noche lo retomé sobre esa base. Domingo, 20:13, lo archivé todo: «forget about previous session, I archived the previous project and to start a new one with better prompt». 23:01: foto, análisis con un modelo de visión, enlaces de tienda artículo por artículo. 00:04: «I’m going to sleep […] please go as far as you can in full autonomy». Por la mañana había detección en streaming, fichas de revisión y recorridos de prueba automatizados.&lt;/p&gt;
&lt;p&gt;Misma idea, mismo desarrollador. La diferencia entre septiembre y este domingo es la calidad de los modelos, y en particular Opus 5.5. ¡¡¡Una bestia!!!&lt;/p&gt;
&lt;h2 id=&quot;el-tiempo-medido&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#el-tiempo-medido&quot; aria-label=&quot;Anchor link for: el-tiempo-medido&quot;&gt;#&lt;/a&gt;
El tiempo, medido&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tipo&lt;/th&gt;&lt;th&gt;Lo que pedí&lt;/th&gt;&lt;th&gt;Tiempo hasta el commit&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;FEAT&lt;/td&gt;&lt;td&gt;«ajoute la langue espagnole à l’application» [añade el español a la aplicación] (Lukarne)&lt;/td&gt;&lt;td&gt;5 min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BUG&lt;/td&gt;&lt;td&gt;Los vecinos a 2500 km: «je suis sur Londres mais la Patagonie est listée» [estoy en Londres pero sale la Patagonia]&lt;/td&gt;&lt;td&gt;5 min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BUG&lt;/td&gt;&lt;td&gt;El logo que solo aparece medio segundo al arrancar&lt;/td&gt;&lt;td&gt;2 min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;FEAT&lt;/td&gt;&lt;td&gt;Más directo, menos imágenes fijas&lt;/td&gt;&lt;td&gt;14 min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;FEAT&lt;/td&gt;&lt;td&gt;El zoom de zambullida «tipo Google Earth», pedido antes de irme a dormir&lt;/td&gt;&lt;td&gt;40 min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;FEAT&lt;/td&gt;&lt;td&gt;Un modo demo que encadena webcams al azar&lt;/td&gt;&lt;td&gt;41 min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BUG&lt;/td&gt;&lt;td&gt;El vídeo reciente que siempre abre un vídeo de 2012 (DropboksTV)&lt;/td&gt;&lt;td&gt;2 min&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;FEAT&lt;/td&gt;&lt;td&gt;«go pour la météo» [adelante con el tiempo] en el reloj&lt;/td&gt;&lt;td&gt;13 min&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Lo que no va más rápido: un cable micro-USB que se suelta, una cuota de YouTube que se reinicia a las 3 de la madrugada, una clave de API que el portal del proveedor rechaza, mi suscripción. Domingo, 16:46: «il me reste que 10% pour notre session en cours» [solo me queda un 10 % para nuestra sesión actual]. Y mi sueño, que acabé metiendo en el plan: «je vais dormir la , avance au maximum de ton autonomie» [me voy a dormir, avanza todo lo que puedas por tu cuenta].&lt;/p&gt;
&lt;p&gt;Lo que todavía no sé: cuántos de estos seis proyectos seguiré usando dentro de un mes. Ahora toca llegar hasta el final, publicar lo que se pueda publicar, alimentar a otros agentes.&lt;/p&gt;
&lt;p&gt;Esta entrada se hizo igual. Un mensaje mío el lunes al final de la tarde, a lo bruto, con mis erratas: «génère moi un article complet […] mettre en avant le délai ridicule que c’est devenu entre l’intention et le concret» [escríbeme un artículo completo […] destaca lo ridículo que se ha vuelto el tiempo entre la intención y lo concreto]. Contarlo todo con transparencia y honestidad. El propio blog estaba en línea 45 minutos después de mi primer mensaje, el lunes a las 4 de la madrugada.&lt;/p&gt;
&lt;p&gt;En fin, ¡buen fin de semana!&lt;/p&gt;
&lt;aside class=&quot;transparence&quot; aria-label=&quot;Cómo se escribió esta entrada&quot;&gt;
  &lt;p class=&quot;transparence-titre&quot;&gt;Cómo se escribió esta entrada&lt;/p&gt;
  &lt;p&gt;Redactada por Claude Opus 5.5 a partir de: un encargo de François en un solo mensaje, sus sesiones de Claude Code (unos 240 mensajes), seis repositorios Git (159 commits), sus &lt;code&gt;DECISIONS.md&lt;/code&gt; y capturas, vídeos grabados por el agente en la Shield, una foto del reloj.&lt;/p&gt;
  &lt;p&gt;Revisada y corregida por François, 19 % del texto reescrito.&lt;/p&gt;
  &lt;p&gt;Traducida del francés por la IA, a partir de la versión revisada. La traducción no se revisó línea por línea.&lt;/p&gt;
&lt;/aside&gt;
</content>
    </entry>
</feed>
