<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://3cucharadas.cl/feed.xml" rel="self" type="application/atom+xml" /><link href="https://3cucharadas.cl/" rel="alternate" type="text/html" hreflang="es" /><updated>2026-07-05T20:48:44-04:00</updated><id>https://3cucharadas.cl/feed.xml</id><title type="html">3 Cucharadas</title><subtitle>Explorando curiosidades</subtitle><author><name>Cristián Labra Olivares</name></author><entry xml:lang="es"><title type="html">RSS en 3 cucharadas: volver a elegir qué lees</title><link href="https://3cucharadas.cl/internet/soberania-digital/rss/" rel="alternate" type="text/html" title="RSS en 3 cucharadas: volver a elegir qué lees" /><published>2026-06-29T00:00:00-04:00</published><updated>2026-06-29T00:00:00-04:00</updated><id>https://3cucharadas.cl/internet/soberania-digital/rss</id><content type="html" xml:base="https://3cucharadas.cl/internet/soberania-digital/rss/"><![CDATA[<p class="text-justify">Hay tecnologías que parecen viejas solo porque dejaron de estar de moda. RSS es una de ellas. No desapareció. No falló técnicamente. Simplemente fue empujado a un costado cuando la web empezó a preferir el feed algorítmico, la notificación, la app cerrada, el “para ti”, el scroll infinito y la idea de que informarse debía ocurrir dentro de plataformas que deciden qué aparece, cuándo aparece y con qué intensidad.</p>

<p class="text-justify">RSS propone algo menos sexy, pero más sano: tú eliges las fuentes, tú decides dónde leerlas, tú puedes exportar tu lista, tú puedes cambiar de lector, tú puedes ordenar el ruido. No eres completamente dueño de la información, porque las fuentes, los medios, los buscadores y los poderes editoriales siguen existiendo. Pero sí eres parcialmente dueño de la forma en que te informas. Y eso, en internet, ya es bastante.</p>

<h2 id="antes-de-las-cucharadas-una-historia-mínima-de-rss">Antes de las cucharadas: una historia mínima de RSS</h2>

<p class="text-justify">RSS nació para una web que todavía olía a páginas personales, blogs, portales y enlaces azules. Su historia tiene varias ramas, disputas y nombres, pero una línea básica sirve para orientarse: en 1999 Netscape publicó RSS 0.90 para My Netscape; después vino RSS 0.91, y más tarde UserLand y Dave Winer empujaron otras versiones que desembocaron en RSS 2.0. El <a href="https://www.rssboard.org/rss-history">historial del RSS Advisory Board</a> registra esa secuencia: RSS 0.90 en marzo de 1999, RSS 0.91 en julio de ese mismo año, una versión de UserLand en 2000 y RSS 2.0 en 2002-2003.</p>

<p class="text-justify">La idea era sencilla: un sitio publica un archivo legible por máquinas con sus novedades. Ese archivo contiene ítems: título, enlace, descripción, fecha, autor u otros metadatos. Un lector RSS visita esos archivos por ti y te muestra lo nuevo. La especificación de <a href="https://web.resource.org/rss/1.0/spec">RSS 1.0</a> lo describía como un formato ligero, extensible y multipropósito para describir y sindicar contenido, con canales compuestos por ítems recuperables por URL.</p>

<p class="text-justify">En esa historia aparece Aaron Swartz, y aparece muy joven. A los 14 años coescribió RSS 1.0, una de las ramas más semánticas y extensibles del estándar, vinculada a RDF. El <a href="https://www.internethalloffame.org/inductee/aaron-swartz/">Internet Hall of Fame</a> lo resume así: en 2000, a los 14, Swartz coautoró RSS 1.0 y luego participó en un grupo de trabajo del W3C sobre formatos comunes para la web.</p>

<p class="text-justify">Mencionarlo no es adorno biográfico. Swartz encarna una forma de entender internet: abierta, interoperable, archivable, enlazable, más cerca del conocimiento público que del encierro en plataformas. RSS tiene algo de esa ética. No te pide que mires un muro administrado por una compañía. Te entrega una tubería. Una fuente. Un modo de decir: “cuando publique algo, ven a buscarlo sin pedirle permiso a un algoritmo”. ✊🏼</p>

<p class="text-justify">Durante años, <a href="https://googlereader.blogspot.com/2013/03/powering-down-google-reader.html">Google Reader</a> fue el gran hogar de esa costumbre. Lanzado en 2005, terminó siendo el lugar donde mucha gente armó su dieta informativa. En 2013 Google anunció que lo cerraría el 1 de julio de ese año, argumentando que su uso había bajado y que la empresa quería concentrarse en menos productos. Ese cierre fue un golpe cultural: no mató RSS, pero sí rompió el centro de gravedad de una práctica. Después vino la diáspora: Feedly, NewsBlur, Inoreader, lectores locales, lectores móviles, lectores autohospedados, lectores que aparecieron y desaparecieron.</p>

<p class="text-justify">RSS sobrevivió porque no dependía de una sola empresa. Esa es la gracia.</p>

<h2 id="cucharada-1-rss-como-soberanía-digital-cotidiana">Cucharada 1: RSS como soberanía digital cotidiana</h2>

<p class="text-justify">La soberanía digital suena a concepto de paper, pero en RSS se vuelve una práctica doméstica: elegir fuentes, ordenar carpetas, exportar una lista, leer en el momento propio, ignorar lo que no importa y no depender de un feed que optimiza tu atención para fines ajenos.</p>

<p class="text-justify">Las redes sociales no están diseñadas principalmente para informarte bien. Están diseñadas para retenerte. A veces eso coincide con estar informado; muchas veces coincide con estar irritado, ansioso, entretenido o atrapado. La diferencia es importante. Un lector RSS no elimina sesgos ni garantiza calidad, pero cambia la arquitectura de decisión. En vez de preguntar “qué quiere mostrarme esta plataforma”, preguntas “qué fuentes decidí seguir y qué publicaron”.</p>

<p class="text-justify">La literatura académica sobre personalización algorítmica ayuda a ponerle marco a esta intuición. Urbano Reviglio y Claudio Agosti proponen el concepto de <a href="https://journals.sagepub.com/doi/10.1177/2056305120915613">“soberanía algorítmica”</a> para discutir el poder que tienen las plataformas sobre la personalización, la curaduría y la modificación de conducta. Su punto no es que toda personalización sea mala, sino que buena parte de esa personalización ocurre en sistemas opacos, comerciales y difíciles de negociar socialmente.</p>

<p class="text-justify">También hay una dimensión cognitiva. La atención no es una bodega infinita. La sobrecarga informativa aparece cuando la cantidad de información que se nos exige procesar supera nuestra capacidad de procesarla con sentido. Una revisión sistemática sobre <a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC10322198/">information overload</a> muestra que este no es solo un problema de volumen, sino también de contexto, tareas, tiempo, interrupciones y diseño de los entornos donde leemos.</p>

<p class="text-justify">En el consumo de noticias, esto importa todavía más. Un estudio en <em>Frontiers in Psychology</em> sobre <a href="https://www.frontiersin.org/journals/psychology/articles/10.3389/fpsyg.2022.862626/full">sobrecarga de noticias en redes sociales</a> encontró relaciones significativas entre news overload, evitación de noticias, necesidad de noticias y conductas de filtrado. Dicho en simple: cuando el flujo se vuelve demasiado intenso, las personas no necesariamente se informan mejor; muchas veces filtran a la fuerza, leen en diagonal, se agotan o directamente evitan.</p>

<p class="text-justify">RSS no soluciona todo eso, pero introduce fricción buena. No hay autoplay. No hay “para ti”. No hay ranking emocional automático. No hay una máquina probando qué titular te retiene dos segundos más. Hay una lista. Hay carpetas. Hay leídos y no leídos. Hay una relación más explícita entre fuente, tiempo y atención. 🧘🏼‍♂️</p>

<p class="text-justify">La evidencia empírica sobre feeds algorítmicos es compleja. En un estudio publicado en <em>Science</em> sobre <a href="https://www.science.org/doi/10.1126/science.abp9364">Facebook e Instagram durante la elección estadounidense de 2020</a>, cambiar feeds algorítmicos por feeds cronológicos redujo el tiempo y la actividad dentro de las plataformas, aunque no produjo cambios significativos en varias actitudes políticas durante el período estudiado. Un trabajo más reciente en <em>Nature</em>, sobre <a href="https://www.nature.com/articles/s41586-026-10098-2">el feed algorítmico de X</a>, reportó que activar un feed algorítmico aumentó el engagement y movió algunas opiniones políticas en ciertos temas. No hace falta sacar una conclusión apocalíptica de esto. Basta con una conclusión práctica: importa quién ordena lo que lees. Importa bajo qué incentivos. Importa si puedes salirte.</p>

<p class="text-justify">RSS te devuelve una parte de ese control.</p>

<h2 id="cucharada-2-dónde-leer-dónde-agregar-y-mi-historia-con-rss">Cucharada 2: dónde leer, dónde agregar y mi historia con RSS</h2>

<p class="text-justify">Un agregador es un lector que junta fuentes distintas en un solo lugar. La idea básica es que no tengas que ir sitio por sitio a buscar información, sino que esa información llegue a ti mediante un lector o agregador. La <a href="https://www.bcn.cl/rss/rss">Biblioteca del Congreso Nacional de Chile</a> lo explica de forma simple: RSS permite recibir contenidos actualizados desde sitios web sin tener que visitarlos manualmente uno por uno.</p>

<p class="text-justify">Ese gesto cambia la relación con la web. En vez de abrir veinte pestañas, abres una bandeja. En vez de depender de que una red social te muestre una nota, sigues directamente al sitio que la publica. En vez de perder tus suscripciones cuando una empresa cambia de estrategia, exportas tu OPML y te vas a otro lector.</p>

<p class="text-justify">Mi historia con RSS empezó por ahí, entre 2006 y 2007, con Google Reader. Ahí agregué la mayoría de mis sitios. Ahí aprendí una forma de informarme que era también una forma de perder el tiempo, pero con cierto orden: revisar pendientes, bajar con el teclado, abrir lo interesante, marcar leído, volver al flujo. Era procrastinación, sí, pero una procrastinación +gobernada.</p>

<p class="text-justify">Después vino Android. Y ahí mi app fue <strong>gReader</strong>. De esa primera camada de lectores móviles, gReader tenía algo muy preciso: era suficientemente fea para parecer herramienta, suficientemente rápida para volverse costumbre y suficientemente cómoda para leer mucho sin pensar demasiado en la aplicación misma. En 2010, Gizmodo la puso como medalla de oro entre <a href="https://gizmodo.com/the-best-rss-reader-apps-5687130">lectores RSS para Android</a>, por encima de alternativas como NewsRob y FeedR. No sé si era la mejor en términos absolutos, pero sí era de esas apps que se pegaban a los dedos.</p>

<p class="text-justify">También recuerdo otros fantasmas de esa época. Una app con un cohete como icono, cuyo nombre se me perdió en la memoria, pero que queda ahí como objeto arqueológico: el RSS en Android fue también eso, probar lectores, cambiar interfaces, entusiasmarse por pequeños gestos de navegación. Y recuerdo <strong>Corgi</strong>, una promesa rara y simpática: un perro que te traía el diario al teléfono. <a href="https://www.androidauthority.com/corgi-for-feedly-news-593114/">Corgi for Feedly</a> ponía tus feeds directamente en la pantalla de bloqueo de Android para leer sin abrir la app. En español, <a href="https://www.elespanol.com/elandroidelibre/aplicaciones/20150306/corgi-lee-feedly-pantalla-bloqueo-android-enterate/15998713_0.html">El Android Libre</a> lo describía tal cual: Feedly en el lockscreen, con diseño Material Design, para pasar artículos desde la pantalla bloqueada. La idea era un poco absurda y un poco brillante: llevar el diario a la puerta de la casa, pero la puerta era la pantalla de bloqueo. 🐶</p>

<p>De esa época dejaría esta pequeña constelación Android:</p>

<ol>
  <li><strong>gReader</strong>, mi app de verdad, la que más calzó con el hábito.</li>
  <li><strong>NewsRob</strong>, fuerte en sincronización y lectura offline, muy atada a la era Google Reader.</li>
  <li><strong>FeedR</strong>, una alternativa más independiente dentro de la primera ola Android.</li>
  <li><strong>Press</strong>, más cuidada visualmente y cercana a esa escuela de lectores bonitos.</li>
  <li><strong>Feedly</strong>, el gran sobreviviente de la diáspora post-Google Reader.</li>
</ol>

<p class="text-justify">Cuando Google Reader anunció su cierre, Feedly se movió rápido. En junio de 2013 lanzó <a href="https://www.wired.com/2013/06/feedly-cloud/">Feedly Cloud</a>, una plataforma propia para dejar de depender del backend de Google Reader y facilitar la migración. Eso explica parte de su persistencia: no solo era una app bonita, sino un servicio de sincronización que logró recibir a usuarios que venían con años de carpetas, hábitos y feeds acumulados.</p>

<p class="text-justify">En Windows también usé software de agregación. Ahí conocí Feedly de otra manera: ya no solo como app, sino como servicio sincronizado. Después me pasé a Reeder. Y cada cierto tiempo, por inquietud o aburrimiento, probaba otros lectores en Windows y Linux: lectores más locales, más libres, más feos, más potentes, más minimalistas. Siempre terminaba volviendo a Feedly.</p>

<p class="text-justify">Pero nunca de pago. No por desprecio al producto, sino por escala de uso. Mi consumo de feeds no da como para pagar una suscripción. Esto también es parte de RSS: puede ser muy sofisticado, pero puede seguir siendo austero. Una lista de fuentes, un lector gratuito, algo de disciplina y nada más.</p>

<p class="text-justify">En iOS, <strong>Reeder</strong> merece un párrafo aparte. La app de <a href="https://reederapp.com/">Silvio Rizzi</a> representa una de las líneas más cuidadas de esta tradición: leer bien, navegar rápido, no estorbar. Valoro mucho ese trabajo. Durante años Reeder fue, para mí, la prueba de que un lector RSS podía ser elegante sin convertirse en revista, minimalista sin volverse pobre, potente sin parecer una consola de administración.</p>

<p class="text-justify">Eso sí: me gustaría que la nueva etapa volviera, al menos para quienes leemos RSS de forma más clásica, al sistema previo de pago único y no suscripción. Aquí conviene ser justo: no es que todo Reeder se haya vuelto una sola cosa. La nueva app, <a href="https://apps.apple.com/gb/app/reeder/id6475002485">Reeder</a>, aparece como gratuita con compras dentro de la app y una suscripción mensual o anual; además, según <a href="https://www.macstories.net/reviews/reeder-a-new-approach-to-following-feeds/">MacStories</a>, Reeder+ desbloquea feeds ilimitados y funciones adicionales. Al mismo tiempo, <a href="https://reederapp.com/classic/">Reeder Classic</a> sigue disponible como versión anterior para quienes prefieren una experiencia tradicional de RSS y read later. Aun así, mi preferencia sigue siendo clara: en lectores RSS, pago único antes que suscripción, salvo que el volumen de lectura justifique pagar infraestructura todos los meses.</p>

<p class="text-justify">Hoy el mapa se podría ordenar así: para empezar rápido, Feedly o Inoreader; para lectura local y privacidad, Feeder; para autohospedaje, FreshRSS, Tiny Tiny RSS o NewsBlur; para leer bonito en Apple, Reeder o Reeder Classic. Pero lo esencial no es la app. Lo esencial es el archivo: el OPML. Ese pequeño mapa exportable de tus fuentes. Tu jardín de enlaces vivos.</p>

<h2 id="cucharada-3-lo-que-viene-después-del-rss-clásico">Cucharada 3: lo que viene después del RSS clásico</h2>

<p class="text-justify">RSS no tiene por qué quedarse en “seguir blogs”. Puede ser una infraestructura personal para leer la web.</p>

<p class="text-justify"><strong>Primero</strong>, podemos hacer feeds donde no los hay. Hay sitios que no publican RSS, pero igual tienen patrones: una página de noticias, una sección de comunicados, una agenda, una lista de documentos, una página institucional que cambia cada cierto tiempo. Herramientas como <a href="https://github.com/RSS-Bridge/rss-bridge">RSS-Bridge</a> existen precisamente para generar feeds de sitios que no tienen uno. <a href="https://github.com/DIYgod/RSSHub">RSSHub</a> va en la misma dirección: una red y proyecto open source para crear rutas RSS desde muchas fuentes distintas. Y herramientas como <a href="https://createfeed.fivefilters.org/">Feed Creator de FiveFilters</a> permiten generar feeds a partir de elementos de una página web que no ofrece RSS propio.</p>

<p class="text-justify"><strong>Segundo</strong>, podemos convertir feeds pobres en feeds útiles. Muchos medios entregan solo título y bajada para obligarte a entrar al sitio. Eso puede tener sentido para su negocio, pero para lectura personal a veces es una molestia. Herramientas de extracción de texto completo permiten limpiar artículos, quitar ruido visual y dejar una versión legible. El propio ecosistema de <a href="https://www.fivefilters.org/">FiveFilters</a> existe alrededor de esa idea: tomar contenido web y transformarlo en algo más portable, legible y procesable.</p>

<p class="text-justify"><strong>Tercero</strong>, podemos hacer digest o resumen propios. No todo merece ser leído al instante. Ese resumen no debería reemplazar la fuente. Debería apuntar hacia ella. El LLM no decide qué existe; ayuda a comprimir lo que tú ya decidiste seguir.</p>

<p class="text-justify"><strong>Cuarto</strong>, podemos mezclar RSS con mensajería. Un feed puede terminar en Telegram, en correo, en una página estática, en una base de datos personal, en un dashboard, en un bot que avisa solo cuando aparece cierta palabra. También puede funcionar al revés: newsletters convertidas en feeds, canales convertidos en resúmenes, sitios sin RSS convertidos en fuentes vigiladas. La web, cuando se deja conectar, vuelve a ser menos una línea de tiempo y más una caja de herramientas.</p>

<p class="text-justify"><strong>Quinto</strong>, podemos compartir mapas de lectura. Un OPML público es una invitación a husmear la dieta informativa de alguien. No como performance de influencia, sino como gesto de infraestructura: “estas son mis fuentes, llévatelas, rómpelas, cámbialas, impórtalas, arma las tuyas”.</p>

<figure class=""><a href="/assets/images/rss-widget-opml-home.png" class="image-popup" title="Figura 1 — Muestra local del widget RSS a los que sigo en la portada de 3 Cucharadas, con descarga del OPML público que alimenta esta dieta informativa.
"><img src="/assets/images/rss-widget-opml-home.png" alt="Captura local del widget RSS a los que sigo en 3 Cucharadas, con enlace de descarga al OPML público del sitio." /></a><figcaption>
      <strong>Figura 1</strong> — Muestra local del widget <strong>RSS a los que sigo</strong> en la portada de 3 Cucharadas, con descarga del OPML público que alimenta esta dieta informativa.

    </figcaption></figure>

<p class="text-justify">Ese es el cierre natural de este post: parte por probar. No hace falta migrar toda tu vida informativa. Basta con elegir diez fuentes que de verdad quieras seguir: un medio, un blog, una revista académica, una cuenta institucional, un podcast, una página rara que siempre olvidas revisar. Las agregas a un lector. Las ordenas. Las lees por una semana. Después decides.</p>

<p class="text-justify">Y para partir, puedes husmear <a href="/assets/feedly-subscriptions.opml">mi OPML</a>: mi archivo con todos mis feeds, mis obsesiones, mis sitios muertos, mis fuentes persistentes, mis carpetas probablemente mal nombradas.</p>

<p class="text-justify">RSS no es nostalgia. Es una forma discreta de resistencia cotidiana contra la lectura gobernada por otros.</p>

<p><strong>Gobierna cómo lees las noticias.</strong></p>

<figure class=""><a href="/assets/images/rss-governance-hero.jpg" class="image-popup" title="Figura 2 — RSS como infraestructura de lectura: menos ruido impuesto por plataformas, más control sobre fuentes, prioridades y ritmo propio.
"><img src="/assets/images/rss-governance-hero.jpg" alt="Ilustración sobre RSS como una forma de gobernar mejor la lectura frente al ruido algorítmico." /></a><figcaption>
      <strong>Figura 2</strong> — RSS como infraestructura de lectura: menos ruido impuesto por plataformas, más control sobre fuentes, prioridades y ritmo propio.

    </figcaption></figure>]]></content><author><name>Cristián Labra Olivares</name></author><category term="internet" /><category term="soberania-digital" /><category term="rss" /><category term="opml" /><category term="feeds" /><category term="soberania-digital" /><category term="lectura" /><category term="algoritmos" /><summary type="html"><![CDATA[RSS no es nostalgia. Es una forma discreta de resistencia cotidiana contra la lectura gobernada por otros.]]></summary></entry><entry xml:lang="es"><title type="html">Multiagentes en 3 cucharadas: lo que me funcionó y lo que no</title><link href="https://3cucharadas.cl/ia/productividad/desarrollo/multiagente-penta-agent-modelos/" rel="alternate" type="text/html" title="Multiagentes en 3 cucharadas: lo que me funcionó y lo que no" /><published>2026-06-26T20:00:00-04:00</published><updated>2026-06-26T20:00:00-04:00</updated><id>https://3cucharadas.cl/ia/productividad/desarrollo/multiagente-penta-agent-modelos-v2</id><content type="html" xml:base="https://3cucharadas.cl/ia/productividad/desarrollo/multiagente-penta-agent-modelos/"><![CDATA[<p class="text-justify">Esto empezó como una molestia práctica: tareas largas que se cortaban por cuota, conversaciones que quedaban demasiado cargadas y revisiones que exigían copiar contexto entre ventanas de forma incómoda e ineficiente. Para resolverlo armé un multiagente en VS Code, sobre Arch Linux, y llamé primero tri-agent y luego de un par de meses ya es <code class="language-plaintext highlighter-rouge">penta-agent</code>, una forma todavía imperfecta de coordinar agentes, roles, permisos y trazas dentro de mi flujo.</p>

<p class="text-justify">No es algo nuevo ni una promesa de autonomía total, de hecho mantenerlo da harta pega. Pero, es un contrato local de trabajo que ordena quién ejecuta, quién revisa, cuándo se usa MCP, cuándo entra Gemini/Antigravity, cuándo Copilot queda como apoyo, qué skills se cargan y qué evidencia o producto queda al cierre.</p>

<p class="text-justify">Lo cuento desde casos de uso concretos míos: minutas, revisión normativa, de planillas, modelos estadísticos, scripts de automatización en server de la casa, timers de sistema, nube propia, seguridad del router, backups, blog y mantenimiento cotidiano. En todos esos casos me ha servido tener algo de “gobernanza” agéntica. Quizás una falsa sensación de soberanía digital también.</p>

<p class="text-justify">La tesis es simple: un sistema multiagente sin roles, permisos ni trazas puede parecer sofisticado, pero en la práctica se parece demasiado a una reunión sin acta.</p>

<p><strong>Tres ideas para comenzar:</strong></p>

<ul>
  <li><strong>Codex me ha funcionado como ejecutor principal</strong>: lee archivos, aplica parches, corre validaciones y puede cerrar diffs con evidencia. No es infalible, por eso no debería autovalidarse en cambios críticos.</li>
  <li><strong>Claude me ha servido como revisor fuerte (sobre todo con Opus)</strong>: revisa arquitectura, normativa, supuestos estadísticos y riesgos argumentales. Lo uso como freno, y apoyo al ejecutor principal.</li>
  <li><strong>Gemini/Antigravity, Copilot y LiteLLM (con DeepSeek y Z.ai) sirven mejor acotados</strong>: exploración, validación, canary o tareas pequeñas. Cuando empiezan a decidir con poco contexto, el flujo empeora.</li>
</ul>

<h2 id="cucharada-1-el-problema-no-era-usar-agentes-era-no-perder-continuidad">Cucharada 1: el problema no era usar agentes, era no perder continuidad</h2>

<p class="text-justify">En una tarea larga, el costo de una pausa no es solo el tiempo sin respuesta. Lo más caro es perder continuidad: qué se estaba probando, qué archivo cambió, qué hipótesis falló, qué validación quedó pendiente y qué contexto ya no conviene seguir arrastrando.</p>

<p class="text-justify">Mi primer error fue tratar cada modelo/agente como una “segunda opinión” o validación simétrica. Eso no escala. En una minuta o una revisión normativa, terminaba con comentarios útiles pero difíciles de reconciliar.</p>

<p class="text-justify">La solución fue más aburrida y más útil: separar roles. No porque sea “la” forma correcta para todo el mundo, sino porque en mi flujo baja el costo de volver a una tarea, sin recapitular era alto.</p>

<p class="text-justify">Me sirve leer la convergencia de proveedores desde ahí. Codex documenta configuración, sandbox, permisos, MCP, <code class="language-plaintext highlighter-rouge">AGENTS.md</code>, skills y subagentes; GitHub Copilot admite instrucciones de repositorio; Gemini Code Assist describe un agent mode con herramientas, MCP y aprobación de cambios; y Claude Code permite hooks en puntos como <code class="language-plaintext highlighter-rouge">PreToolUse</code>, <code class="language-plaintext highlighter-rouge">PostToolUse</code> y <code class="language-plaintext highlighter-rouge">SessionStart</code>.<sup id="fnref:openai-config"><a href="#fn:openai-config" class="footnote" rel="footnote" role="doc-noteref">1</a></sup><sup id="fnref:github-instructions"><a href="#fn:github-instructions" class="footnote" rel="footnote" role="doc-noteref">2</a></sup><sup id="fnref:gemini-agent"><a href="#fn:gemini-agent" class="footnote" rel="footnote" role="doc-noteref">3</a></sup><sup id="fnref:claude-hooks"><a href="#fn:claude-hooks" class="footnote" rel="footnote" role="doc-noteref">4</a></sup></p>

<p class="table-caption"><strong>Tabla 2</strong> — Roles actuales en <code class="language-plaintext highlighter-rouge">penta-agent</code></p>

<table>
  <thead>
    <tr>
      <th>Componente</th>
      <th>Rol real</th>
      <th>Límite que le impongo</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>ChatGPT/Codex</td>
      <td>Orquestador técnico local, planner y ejecutor</td>
      <td>No autovalidarse como única fuente de verdad en cambios críticos</td>
    </tr>
    <tr>
      <td>Claude</td>
      <td>Reviewer, auditor y co-planificador</td>
      <td>No tomar control operativo por defecto</td>
    </tr>
    <tr>
      <td>Gemini/Antigravity</td>
      <td>Explorer, validator y fallback</td>
      <td>No entrar al critical path salvo decisión explícita</td>
    </tr>
    <tr>
      <td>Copilot</td>
      <td>Canary y soporte IDE/GitHub-native</td>
      <td>No tratarlo como árbitro arquitectónico independiente</td>
    </tr>
    <tr>
      <td>LiteLLM sidecar</td>
      <td>Delegación barata y estrecha</td>
      <td>No usarlo para arquitectura, seguridad ni decisiones finales; hoy lo uso acotado con DeepSeek y Z.ai</td>
    </tr>
    <tr>
      <td>Humano</td>
      <td>Cierre, privacidad y aceptación</td>
      <td>No delegar criterio final cuando hay riesgo</td>
    </tr>
  </tbody>
</table>

<p>La arquitectura local lo vuelve explícito. En <code class="language-plaintext highlighter-rouge">routing.yaml</code>, la regla <code class="language-plaintext highlighter-rouge">penta_agent_ops</code> mantiene a Codex como <code class="language-plaintext highlighter-rouge">primary</code>, a Claude como <code class="language-plaintext highlighter-rouge">reviewer</code>, a Gemini como validador/fallback y al humano como checkpoint:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">id</span><span class="pi">:</span> <span class="s">penta_agent_ops</span>
<span class="na">planner</span><span class="pi">:</span> <span class="s">codex</span>
<span class="na">primary</span><span class="pi">:</span> <span class="s">codex</span>
<span class="na">reviewer</span><span class="pi">:</span> <span class="s">claude</span>
<span class="na">escalate_to</span><span class="pi">:</span> <span class="s">humano</span>
<span class="na">validator_chain</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">gemini</span><span class="pi">]</span>
<span class="na">fallback_chain</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">gemini</span><span class="pi">]</span>
<span class="na">planning</span><span class="pi">:</span>
  <span class="na">proactive_skills</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">handoff-protocol</span><span class="pi">,</span> <span class="nv">recall-context</span><span class="pi">]</span>
  <span class="na">mcp_policy</span><span class="pi">:</span>
    <span class="na">mode</span><span class="pi">:</span> <span class="s">conditional</span>
    <span class="na">allowed_paths</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">claude_to_codex_mcp</span><span class="pi">,</span> <span class="nv">gemini_to_codex_mcp</span><span class="pi">]</span>
  <span class="na">provider_roles</span><span class="pi">:</span>
    <span class="na">planning_sidecars</span><span class="pi">:</span>
      <span class="na">canary</span><span class="pi">:</span> <span class="s">copilot</span>
</code></pre></div></div>

<p class="text-justify">El detalle clave es <code class="language-plaintext highlighter-rouge">mcp_policy.mode: conditional</code>. No todo se manda por MCP. No todo merece handoff. No todo merece un segundo proveedor. La evaluación luego de algunas iteraciones la hice proactiva, al igual que con los skills, que los activadores fuesen bien explicitos. Al principio no se activaban cuando querían o los handoffs eran escasos.</p>

<hr />

<h2 id="cucharada-2-el-repositorio-como-contrato-de-trabajo">Cucharada 2: el repositorio como contrato de trabajo</h2>

<p class="text-justify">La pieza que más me ayudó no fue un modelo. Fue una regla de arranque: si una tarea toca multiagente, MCP, Claude, Gemini, Copilot, routing, handoffs o <code class="language-plaintext highlighter-rouge">penta-agent</code>, primero se lee el canon local.</p>

<p>En mi caso, ese canon vive en archivos como:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">router/routing.yaml</code></li>
  <li><code class="language-plaintext highlighter-rouge">shared-references/arquitectura-multiagente.md</code></li>
  <li><code class="language-plaintext highlighter-rouge">playbooks/puente-mcp-codex.md</code></li>
  <li><code class="language-plaintext highlighter-rouge">.mcp.json</code></li>
</ul>

<p class="text-justify">Esto evita un vicio frecuente: hacer uso genérico de CLIs, modelos y comandos antes de entender el “contrato” u objetivo del proyecto. En cosas chicas puede no importar. En una revisión normativa, una corrida estadística o un ajuste de seguridad local, sí importa, ya que la deriva gasta tokens como loco, y a veces termina varado en cualquier lugar.</p>

<p>Un <code class="language-plaintext highlighter-rouge">AGENTS.md</code> útil no necesita ser una novela, gasta contexto, tiene que evitar malas prácticas creo yo:</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Reglas multiagente del workspace</span>

Si el usuario menciona trabajo multiagente, MCP, Claude, Gemini,
Copilot, routing, handoff o penta-agent:
<span class="p">
1.</span> Usar <span class="sb">`penta-agent/`</span> como source of truth.
<span class="p">2.</span> Leer primero routing, arquitectura, puente MCP y configuración MCP.
<span class="p">3.</span> No hacer probing genérico de CLIs antes de leer el canon.
<span class="p">4.</span> Delegar a Antigravity solo mediante <span class="sb">`scripts/agent/agy-bridge`</span>.
<span class="p">5.</span> No entregar secretos, <span class="sb">`.env`</span>, llaves ni credenciales a proveedores externos.
</code></pre></div></div>

<p class="text-justify">La literatura reciente pareciera ir en una dirección parecida, pero con una advertencia sana. Galster et al. describen estos artefactos como mecanismos versionables para configurar herramientas agenticas y observan que <code class="language-plaintext highlighter-rouge">AGENTS.md</code> emerge como estándar interoperable.<sup id="fnref:galster-config"><a href="#fn:galster-config" class="footnote" rel="footnote" role="doc-noteref">5</a></sup> Arabat y Sayagh proponen mirarlos como “instructions-as-code”, no como notas al margen.<sup id="fnref:instructions-code"><a href="#fn:instructions-code" class="footnote" rel="footnote" role="doc-noteref">6</a></sup> Por otro lado, Gloaguen et al. advierten que los context files pueden reducir éxito y aumentar costo cuando agregan requisitos innecesarios.<sup id="fnref:agents-md-eval"><a href="#fn:agents-md-eval" class="footnote" rel="footnote" role="doc-noteref">7</a></sup> En mi experiencia, hay que buscar bien el equilibrio y estar dispuesto a tunear de forma constante.</p>

<h3 id="skills-procedimientos-no-prompts-eternos">Skills: procedimientos, no prompts eternos</h3>

<p>Las skills me han servido cuando actúan como procedimientos reutilizables con activación clara, límites y referencias. Una skill de publicación, por ejemplo, no debería decir “escribe bonito”; debería decir cosas verificables:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">jekyll-post</span>
<span class="na">description</span><span class="pi">:</span> <span class="s">Posts Jekyll con front matter, drafts/posts, build y publicacion reproducible.</span>
</code></pre></div></div>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">-</span> Preparar front matter correcto y validar build.
<span class="p">-</span> Mantener claims fechados y trazables.
<span class="p">-</span> Revisar front matter y guía editorial.
</code></pre></div></div>

<p class="text-justify">La pregunta mínima para una skill es: cuándo se activa, qué no debe hacer, qué archivos debe leer y qué salida permite verificar que hizo bien su trabajo. Eso calza con la carga progresiva descrita por Anthropic: metadata primero, instrucciones cuando la skill se activa, y recursos o scripts solo si hacen falta.<sup id="fnref:claude-skills"><a href="#fn:claude-skills" class="footnote" rel="footnote" role="doc-noteref">8</a></sup> También calza con SkillJuror, que muestra que la organización de una skill cambia cómo los agentes buscan y aplican conocimiento, aunque el beneficio depende de que los recursos sean accionables.<sup id="fnref:skilljuror"><a href="#fn:skilljuror" class="footnote" rel="footnote" role="doc-noteref">9</a></sup></p>

<p class="text-justify">La advertencia de seguridad es igualmente importante: <code class="language-plaintext highlighter-rouge">SKILL.md</code> no es documentación pasiva.<sup id="fnref:skill-supply-chain"><a href="#fn:skill-supply-chain" class="footnote" rel="footnote" role="doc-noteref">10</a></sup> Si una skill trae scripts, instrucciones ambiguas o metadata manipulable, se parece más a instalar software que a pegar un prompt inocente.</p>

<h3 id="mcp-puente-pero-aún-no-le-saco-el-jugo">MCP: puente, pero aún no le saco el jugo</h3>

<p>El MCP real de <code class="language-plaintext highlighter-rouge">penta-agent</code> es deliberadamente pequeño:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"mcpServers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"codex"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"stdio"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"scripts/codex_mcp.sh"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"args"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"mcp-server"</span><span class="p">],</span><span class="w">
      </span><span class="nl">"env"</span><span class="p">:</span><span class="w"> </span><span class="p">{}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p class="text-justify">La idea no es que todos los agentes se conecten con todos. El camino preferido es <strong>Claude/Gemini hacia Codex</strong> cuando necesitan filesystem, comandos, tests o edición local. Codex hacia Claude o Antigravity usa CLI/handoff controlado. No asumo bridge bidireccional ni <code class="language-plaintext highlighter-rouge">filesystem</code> MCP universal.</p>

<p class="text-justify">Esto también es una decisión de seguridad. La documentación oficial de MCP enumera riesgos como confused deputy, token passthrough, SSRF, secuestro de sesión y compromiso de servidores locales.<sup id="fnref:mcp-security"><a href="#fn:mcp-security" class="footnote" rel="footnote" role="doc-noteref">11</a></sup> La investigación reciente sobre tool poisoning en MCP insiste en que el problema crítico muchas veces está del lado cliente: metadata maliciosa, baja visibilidad de parámetros y confianza implícita.<sup id="fnref:mcp-threat"><a href="#fn:mcp-threat" class="footnote" rel="footnote" role="doc-noteref">12</a></sup>. Aún no le saco todo el provecho.</p>

<h3 id="handoffs-el-antídoto-contra-yo-le-avisé">Handoffs: el antídoto contra “yo le avisé”</h3>

<p>Un handoff no es decir “que lo revise Claude”. Un handoff útil debe dejar rastro mínimo:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HANDOFF-TRACE: codex le solicita apoyo a claude (model: sonnet) via CLI
MODEL-REPORT: {"agent":"codex","provider":"openai","model":"__default__","source":"self_report"}
MODEL-REPORT: {"agent":"claude","provider":"anthropic","model":"sonnet","source":"self_report"}
</code></pre></div></div>

<p>Y debe separar lo básico:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">metadata</span><span class="pi">:</span>
  <span class="na">from</span><span class="pi">:</span> <span class="s">codex</span>
  <span class="na">to</span><span class="pi">:</span> <span class="s">claude</span>
  <span class="na">via</span><span class="pi">:</span> <span class="s">CLI</span>
  <span class="na">skill</span><span class="pi">:</span> <span class="s">handoff-protocol</span>

<span class="na">contexto_esencial</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">que se hizo</span>
  <span class="pi">-</span> <span class="s">que se descarto</span>
  <span class="pi">-</span> <span class="s">que falta validar</span>

<span class="na">tarea_para_receptor</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">revisar claims</span>
  <span class="pi">-</span> <span class="s">detectar riesgos</span>
  <span class="pi">-</span> <span class="s">no modificar archivos</span>

<span class="na">verificacion</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">pruebas corridas</span>
  <span class="pi">-</span> <span class="s">fuentes consultadas</span>
  <span class="pi">-</span> <span class="s">decision final</span>
</code></pre></div></div>

<p class="text-justify">Esto parece burocracia hasta que algo falla. Cuando falla, la traza permite saber si el problema fue contexto insuficiente, modelo inadecuado, mala ruta, salida ambigua, cuota, permisos, sandbox o una instrucción mal escrita. OpenAI propone una lógica semejante en su loop de mejora de agentes: usar trazas, feedback y evaluaciones para modificar el arnés, no solo para pedirle al modelo que “lo haga mejor”.<sup id="fnref:openai-loop"><a href="#fn:openai-loop" class="footnote" rel="footnote" role="doc-noteref">13</a></sup> Esto me ha servido para usar la skill recall-context luego, ya que con una buena traza recupero trabajo previo de forma bien eficiente entre agentes.</p>

<hr />

<h2 id="cucharada-3-lo-que-aprendí-haciendo-que-fallara">Cucharada 3: lo que aprendí haciendo que fallara</h2>

<p class="text-justify">La lista de errores propios vale más que la lista de herramientas. Este post más que vitrina, ojalá sirva de bitácora y probablemente añeje pronto, pero ojalá le sirva a más de alguien.</p>

<p class="table-caption"><strong>Tabla 3</strong> — Errores propios y controles actuales</p>

<table>
  <thead>
    <tr>
      <th>Error</th>
      <th>Cómo se veía</th>
      <th>Control actual</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tratar modelos como equivalentes</td>
      <td>Cualquier proveedor podía opinar de cualquier cosa</td>
      <td>Roles explícitos: primary, reviewer, explorer, validator, canary</td>
    </tr>
    <tr>
      <td>Fan-out automático</td>
      <td>Pedía segundas opiniones por costumbre</td>
      <td>Evaluar siempre, invocar solo con señal suficiente</td>
    </tr>
    <tr>
      <td>Model IDs frágiles</td>
      <td>Un rename rompía scripts o ejemplos</td>
      <td>Usar <code class="language-plaintext highlighter-rouge">__default__</code>, aliases y discovery diaria</td>
    </tr>
    <tr>
      <td>Sidecar declarado listo demasiado pronto</td>
      <td>El proxy arrancaba, pero el proveedor fallaba por saldo/cuota</td>
      <td>Separar “proxy vivo” de “proveedor usable”</td>
    </tr>
    <tr>
      <td>Context files demasiado largos</td>
      <td>El agente obedecía reglas irrelevantes y exploraba de más</td>
      <td>Instrucciones mínimas, accionables y fechadas</td>
    </tr>
    <tr>
      <td>MCP como solución universal</td>
      <td>Más servidores, más confianza implícita</td>
      <td>MCP condicional, consentimiento, sandbox y mínimos permisos</td>
    </tr>
    <tr>
      <td>Memoria vectorial como fuente de verdad</td>
      <td>Riesgo de drift por dimensiones o índices derivados</td>
      <td>JSONL como fuente; Qdrant/FastEmbed como índice reconstruible</td>
    </tr>
    <tr>
      <td>Copilot como segundo proveedor fuerte</td>
      <td>No siempre aporta independencia real</td>
      <td>Usarlo como canary/support, no como árbitro</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">La parte de memoria merece un párrafo. En <code class="language-plaintext highlighter-rouge">penta-agent</code>, la memoria operativa vive en archivos append-only como <code class="language-plaintext highlighter-rouge">experience-events.jsonl</code>, <code class="language-plaintext highlighter-rouge">experience-lessons.yaml</code> e <code class="language-plaintext highlighter-rouge">interaction-metrics.jsonl</code>. Qdrant y FastEmbed ayudan a recuperar experiencias, pero son derivados. Si cambia el embedding o aparece una dimensión incompatible, se reconstruye el índice desde JSONL. Después de pelear con ese tipo de drift, no quiero que la fuente de verdad sea frágil.</p>

<p class="text-justify">El sidecar de LiteLLM sigue la misma filosofía. Sirve para delegar tareas baratas y acotadas a aliases como <code class="language-plaintext highlighter-rouge">cheap</code>, <code class="language-plaintext highlighter-rouge">cheap-code</code> o <code class="language-plaintext highlighter-rouge">cheap-reasoner</code>, pero no para arquitectura, seguridad ni decisiones finales. Además, el smoke real de proveedor importa más que el contenedor sano. Si DeepSeek responde <code class="language-plaintext highlighter-rouge">Insufficient Balance</code>, el sistema no está listo; solo aprendimos que Docker sabe prender una luz.</p>

<hr />

<h2 id="cierre-bucle-de-optimización">Cierre: bucle de optimización</h2>

<p class="text-justify">No conviene mirar mi stack como si fuera plantilla universal, no lo es. Lo que sí puede servir es tomar elementos de la lógica: contratos pequeños para no depender de memoria humana ni de entusiasmo del momento. Dejé una versión pública y sanitizada del stack en <a href="https://github.com/tatanlabra/penta-agent"><code class="language-plaintext highlighter-rouge">tatanlabra/penta-agent</code></a>. No es un volcado de mi entorno local: quité memoria runtime, rutas privadas, logs, <code class="language-plaintext highlighter-rouge">.env</code>, credenciales, IPs internas y cualquier cosa que pudiera revelar configuración personal. Quien lo clone debería tratarlo como plantilla y revisar los placeholders de <code class="language-plaintext highlighter-rouge">AGENTS.md</code>, <code class="language-plaintext highlighter-rouge">.mcp.json</code>, <code class="language-plaintext highlighter-rouge">router/routing.yaml</code>, <code class="language-plaintext highlighter-rouge">scripts/agent/agy-bridge</code> y <code class="language-plaintext highlighter-rouge">skills/</code> antes de usarlo.</p>

<p class="text-justify"><code class="language-plaintext highlighter-rouge">penta-agent</code> me ha servido no porque tenga muchos agentes, sino porque tiene frenos: roles, rutas, skills, permisos, handoffs, memoria reconstruible y validación. Eso no lo vuelve universal ni superior. Lo vuelve auditable para mis problemas. El <em>vibe coding</em> nombra bien la primera sensación de fluidez: pedir, ver aparecer código, corregir y seguir. Pero cuando el flujo madura, la pregunta cambia: qué tan eficiente, elegante y verificable es la solución que obtienes.</p>

<hr />

<h2 id="referencias-técnicas">Referencias técnicas</h2>

<hr />
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:openai-config">
      <p>OpenAI Developers, “Configuration Reference — Codex”, consultado el 21 de junio de 2026. Documenta configuración, permisos, sandbox, MCP, <code class="language-plaintext highlighter-rouge">AGENTS.md</code>, skills y subagentes en Codex. <a href="https://developers.openai.com/codex/config-reference">https://developers.openai.com/codex/config-reference</a> <a href="#fnref:openai-config" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:github-instructions">
      <p>GitHub Docs, “Adding repository custom instructions for GitHub Copilot”, consultado el 21 de junio de 2026. Documenta instrucciones de repositorio y formatos asociados a Copilot. <a href="https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions">https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions</a> <a href="#fnref:github-instructions" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:gemini-agent">
      <p>Google Developers, “Use the Gemini Code Assist agent mode”, consultado el 21 de junio de 2026. Describe agent mode en IDE, uso de herramientas, MCP y aprobación de acciones. <a href="https://developers.google.com/gemini-code-assist/docs/use-agentic-chat-pair-programmer">https://developers.google.com/gemini-code-assist/docs/use-agentic-chat-pair-programmer</a> <a href="#fnref:gemini-agent" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:claude-hooks">
      <p>Anthropic, “Hooks reference — Claude Code Docs”, consultado el 21 de junio de 2026. Describe hooks como puntos de control del ciclo de vida, incluidos <code class="language-plaintext highlighter-rouge">PreToolUse</code>, <code class="language-plaintext highlighter-rouge">PostToolUse</code> y <code class="language-plaintext highlighter-rouge">SessionStart</code>. <a href="https://code.claude.com/docs/en/hooks">https://code.claude.com/docs/en/hooks</a> <a href="#fnref:claude-hooks" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:galster-config">
      <p>Matthias Galster et al., “Configuring Agentic AI Coding Tools: An Exploratory Study”, arXiv:2602.14690, 2026. Analiza mecanismos como context files, skills, subagentes, hooks, settings y MCP. <a href="https://arxiv.org/abs/2602.14690">https://arxiv.org/abs/2602.14690</a> <a href="#fnref:galster-config" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:instructions-code">
      <p>Ali Arabat y Mohammed Sayagh, “Toward Instructions-as-Code: Understanding the Impact of Instruction Files on Agentic Pull Requests”, arXiv:2606.13449, 2026. Analiza pull requests agenticos y concluye que las instrucciones no mejoran automáticamente el desempeño. <a href="https://arxiv.org/abs/2606.13449">https://arxiv.org/abs/2606.13449</a> <a href="#fnref:instructions-code" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:agents-md-eval">
      <p>Thibaud Gloaguen et al., “Evaluating AGENTS.md: Are Repository-Level Context Files Helpful for Coding Agents?”, arXiv:2602.11988, 2026. Reporta que context files pueden reducir éxito y elevar costo cuando agregan requisitos innecesarios. <a href="https://arxiv.org/abs/2602.11988">https://arxiv.org/abs/2602.11988</a> <a href="#fnref:agents-md-eval" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:claude-skills">
      <p>Anthropic, “Agent Skills — Claude API Docs”, consultado el 21 de junio de 2026. Describe skills como capacidades modulares con instrucciones, metadata, scripts y referencias, cargadas por etapas. <a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview">https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview</a> <a href="#fnref:claude-skills" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:skilljuror">
      <p>Zhiyu Chen et al., “SkillJuror: Measuring How Agent Skill Organization Changes Runtime Behavior”, arXiv:2606.11543, 2026. Evalúa organización de skills y carga progresiva. <a href="https://arxiv.org/abs/2606.11543">https://arxiv.org/abs/2606.11543</a> <a href="#fnref:skilljuror" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:skill-supply-chain">
      <p>Shoumik Saha, Kazem Faghih y Soheil Feizi, “Under the Hood of SKILL.md: Semantic Supply-chain Attacks on AI Agent Skill Registry”, arXiv:2605.11418, 2026. Advierte que la metadata e instrucciones de <code class="language-plaintext highlighter-rouge">SKILL.md</code> pueden manipular descubrimiento, selección y gobernanza de skills. <a href="https://arxiv.org/abs/2605.11418">https://arxiv.org/abs/2605.11418</a> <a href="#fnref:skill-supply-chain" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:mcp-security">
      <p>Model Context Protocol, “Security Best Practices”, consultado el 21 de junio de 2026. Enumera riesgos y mitigaciones para implementaciones MCP. <a href="https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices">https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices</a> <a href="#fnref:mcp-security" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:mcp-threat">
      <p>Charoes Huang, Xin Huang, Ngoc Phu Tran y Amin Milani Fard, “Model Context Protocol Threat Modeling and Analyzing Vulnerabilities to Prompt Injection with Tool Poisoning”, arXiv:2603.22489, 2026. Aplica STRIDE/DREAD a MCP y destaca tool poisoning como vulnerabilidad crítica del lado cliente. <a href="https://arxiv.org/abs/2603.22489">https://arxiv.org/abs/2603.22489</a> <a href="#fnref:mcp-threat" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:openai-loop">
      <p>OpenAI Cookbook, “Build an Agent Improvement Loop with Traces, Evals, and Codex”, consultado el 21 de junio de 2026. Usa trazas, feedback, evaluaciones y configuración del harness para mejorar agentes. <a href="https://developers.openai.com/cookbook/examples/agents_sdk/agent_improvement_loop">https://developers.openai.com/cookbook/examples/agents_sdk/agent_improvement_loop</a> <a href="#fnref:openai-loop" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Cristián Labra Olivares</name></author><category term="ia" /><category term="productividad" /><category term="desarrollo" /><category term="multiagente" /><category term="multiagente" /><category term="agentic-coding" /><category term="context-engineering" /><category term="codex" /><category term="claude-code" /><category term="gemini" /><category term="antigravity" /><category term="copilot" /><category term="litellm" /><category term="deepseek" /><category term="zai" /><category term="mcp" /><category term="skills" /><category term="agents-md" /><category term="vscode" /><category term="arch-linux" /><summary type="html"><![CDATA[Una experiencia situada con penta-agent: qué me ha servido para coordinar agentes en minutas, normativa, estadística, automatización doméstica, nube propia y seguridad local, sin venderlo como receta universal.]]></summary></entry><entry xml:lang="es"><title type="html">Hiperparámetros con Bayes en 3 cucharadas: menos grilla, más memoria estadística</title><link href="https://3cucharadas.cl/mlops/bayes-hiperparametros/" rel="alternate" type="text/html" title="Hiperparámetros con Bayes en 3 cucharadas: menos grilla, más memoria estadística" /><published>2026-06-20T00:00:00-04:00</published><updated>2026-06-20T00:00:00-04:00</updated><id>https://3cucharadas.cl/mlops/bayes_hiperparametros</id><content type="html" xml:base="https://3cucharadas.cl/mlops/bayes-hiperparametros/"><![CDATA[<p class="text-justify">Imaginemos un modelo tabular con 10 valores de <span class="text-nowrap">learn_rate</span>, 8 de <span class="text-nowrap">max_depth</span>, 5 de <span class="text-nowrap">sample_rate</span> y 5 de <span class="text-nowrap">col_sample_rate</span>. Una grilla cartesiana entrenaría <strong>2.000 modelos</strong>. Con validación cruzada de 5 folds, la cuenta operativa sube a <strong>10.000 ajustes internos</strong>. En una máquina con RAM, VRAM o CPU acotadas, eso no es necesariamente más rigor: puede ser solo una forma cara de ignorar lo aprendido en las evaluaciones anteriores.</p>

<p class="text-justify">Este post propone usar optimización bayesiana (BO) como una capa externa de decisión en Python. No gana siempre. Gana cuando el problema se parece a esto: función objetivo cara, espacio de búsqueda acotado, métrica razonablemente estable y presupuesto limitado.</p>

<p><strong>Tres ideas para comenzar:</strong></p>

<ul>
  <li><strong>BO no asume que el hiperparámetro tenga una distribución particular.</strong> En el caso clásico con procesos gaussianos, lo que se modela probabilísticamente es la función objetivo evaluada en distintos puntos del espacio de hiperparámetros.</li>
  <li><strong>Random search sigue siendo un baseline serio.</strong> Bergstra y Bengio mostraron que puede ser mucho más eficiente que la grilla cuando no todos los hiperparámetros importan por igual. BO parte desde ahí y agrega memoria estadística.</li>
  <li><strong>Optimizar hiperparámetros no arregla una mala función objetivo.</strong> En RSH, por ejemplo, se podría modelar una circularidad (lo que llaman ahora “fuga de información” 🌊). En ecommerce, sin ser mi campo (bienvenidos comentarios) sería confundir propensión con causalidad. En ambos casos, BO puede encontrar más rápido una solución si el diseño predictivo está bien planteado.</li>
</ul>

<hr />

<h2 id="tolerancia-al-contraste-o-cotejo-con-evidencia">Tolerancia al contraste o cotejo con evidencia</h2>

<p class="text-justify">Este post no compara resultados empíricos todavía (segunda patita), pero he probado su funcionamiento en productivo con un par de casos, por lo que viene desde lo empírico con datos reales y trazabilidad completa (SAT: Sistema de Alerta Temprana de Deserción Escolar, y Modelo de Subtramos de vulnerabilidad en RSH, tramos dentro del 40% más vulnerable con EBM).</p>

<p class="table-caption"><strong>Tabla 1</strong> — Evidencia mínima para sostener el enfoque</p>

<table>
  <thead>
    <tr>
      <th>Punto</th>
      <th>Evidencia</th>
      <th>Implicancia práctica</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>H2O resuelve bien el entrenamiento, pero no trae BO como búsqueda nativa estándar</td>
      <td><a href="https://docs.h2o.ai/h2o/latest-stable/h2o-docs/grid-search.html">H2O Grid Search</a> documenta grillas cartesianas y aleatorias.</td>
      <td>Si queremos una búsqueda secuencial informada, H2O puede quedar como motor de entrenamiento y Python como capa de optimización externa. La separación es limpia: H2O entrena; Optuna, SMAC, BoTorch o <code class="language-plaintext highlighter-rouge">skopt</code> deciden el próximo punto.</td>
    </tr>
    <tr>
      <td>Para este post, Optuna es una opción más práctica que <code class="language-plaintext highlighter-rouge">gp_minimize</code></td>
      <td><a href="https://optuna.org/">Optuna</a> está diseñado como framework de HPO, con estudios, trials, persistencia, samplers y pruners. Además, su <a href="https://optuna.readthedocs.io/en/stable/reference/samplers/generated/optuna.samplers.GPSampler.html"><code class="language-plaintext highlighter-rouge">GPSampler</code></a> ajusta un proceso gaussiano sobre la función objetivo.</td>
      <td>En un flujo H2O + Python, Optuna permite registrar cada corrida, reanudar experimentos y comparar samplers. <code class="language-plaintext highlighter-rouge">gp_minimize</code> sirve para explicar BO con pocas líneas, pero Optuna es más defendible como herramienta de trabajo.</td>
    </tr>
    <tr>
      <td>La normalidad no está en el hiperparámetro, sino en el modelo probabilístico de la función objetivo</td>
      <td>En BO con procesos gaussianos, lo que se modela es la función $f(\theta)$, por ejemplo, la AUC obtenida al entrenar con cierto conjunto de hiperparámetros. Véase <a href="https://scikit-optimize.github.io/stable/modules/generated/skopt.gp_minimize.html"><code class="language-plaintext highlighter-rouge">skopt.gp_minimize</code></a> y <a href="https://optuna.readthedocs.io/en/stable/reference/samplers/generated/optuna.samplers.GPSampler.html"><code class="language-plaintext highlighter-rouge">Optuna GPSampler</code></a>.</td>
      <td>No corresponde decir que “el hiperparámetro sigue una normal”. Lo correcto es decir que, dadas las evaluaciones ya observadas, BO construye una distribución predictiva sobre el desempeño esperado de nuevas configuraciones.</td>
    </tr>
    <tr>
      <td>Random search no es ingenuo: es un baseline fuerte cuando pocos hiperparámetros importan de verdad</td>
      <td><a href="https://jmlr.org/papers/v13/bergstra12a.html">Bergstra y Bengio (2012)</a> muestran que random search puede ser más eficiente que una grilla cuando solo algunas dimensiones concentran la variación relevante.</td>
      <td>La comparación justa no es BO versus grilla enorme, sino BO versus random search con el mismo presupuesto de evaluaciones. Si BO no supera ese baseline, el espacio de búsqueda o el surrogate probablemente no están aportando.</td>
    </tr>
    <tr>
      <td>HPO exige diseño experimental, no solo una librería</td>
      <td><a href="https://arxiv.org/abs/2107.05847">Bischl et al. (2023)</a> ordenan el problema de HPO como una decisión experimental: espacio de búsqueda, presupuesto, remuestreo, métrica, riesgo de sobreajuste y validación externa.</td>
      <td>La optimización debe fijar antes el presupuesto de trials, la métrica objetivo y la separación train/validation/test. En RSH y ecommerce, repetir tuning contra la misma validación puede sobreajustar tanto como ajustar mal el modelo.</td>
    </tr>
    <tr>
      <td>BO puede ahorrar evaluaciones, pero depende del surrogate y de la función de adquisición</td>
      <td><a href="https://www.jmlr.org/papers/v23/21-0888.html">SMAC3, Lindauer et al. (2022)</a> muestra un enfoque robusto de optimización bayesiana para configuraciones de algoritmos; <a href="https://arxiv.org/abs/1910.06403">BoTorch, Balandat et al. (2020)</a> ofrece un marco más flexible para adquisición, restricciones y optimización avanzada.</td>
      <td>“Usar Bayes” no basta. En espacios mixtos, condicionales o con muchas categorías, TPE/SMAC puede ser más práctico que un GP simple; en problemas avanzados, BoTorch es más potente, pero también más exigente.</td>
    </tr>
    <tr>
      <td>Expected Improvement es útil, pero no debe tratarse como receta cerrada</td>
      <td><a href="https://arxiv.org/abs/2310.20708">Ament et al. (2023)</a> revisan problemas numéricos de EI y proponen logEI; otros trabajos recientes muestran que la adquisición puede comportarse mal con ruido, mala inicialización o superficies difíciles.</td>
      <td>En validaciones ruidosas, como CV, validación temporal o muestras pequeñas, conviene fijar semillas, repetir folds o usar métricas menos inestables. La adquisición decide dónde mirar después, no garantiza verdad estadística.</td>
    </tr>
    <tr>
      <td>LLM + BO es una línea interesante, no un reemplazo de la validación</td>
      <td><a href="https://arxiv.org/abs/2402.03921">LLAMBO, Liu et al. (2024)</a>, y trabajos sobre priors o modelos preentrenados para BO, como <a href="https://arxiv.org/abs/2109.08215">HyperBO, Wang et al. (2021)</a>, apuntan a usar conocimiento previo para proponer mejores espacios o puntos iniciales.</td>
      <td>Un modelo de razonamiento puede ayudar a definir rangos, descartar configuraciones absurdas o proponer warm starts. Pero no reemplaza holdout, validación temporal, auditoría de leakage ni análisis sustantivo del target.</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="cucharada-1-dos-problemas-de-ranking-no-dos-juguetes-predictivos">Cucharada 1: dos problemas de ranking, no dos juguetes predictivos</h2>

<p class="text-justify">Quiero usar dos ejemplos con igual peso. Uno viene del mundo público: ordenar hogares por vulnerabilidad relativa usando una muestra pública del RSH (sobre lectura territorial de datos sociales en Chile escribí antes en <a href="/datos/politica-publica/julia/casen/casen2024-julia-waffles-politica-publica/">CASEN 2024 en 3 cucharadas</a>). El otro viene del mundo privado: ordenar clientes, sesiones o contactos según el valor esperado de una acción comercial en ecommerce.</p>

<p class="text-justify">No son problemas equivalentes en lo sustantivo. El primero tiene consecuencias de legitimidad pública; el segundo, de eficiencia comercial. Pero ambos comparten una misma pregunta estadística: si lo importante es ordenar bien los casos, ¿cómo buscamos hiperparámetros que mejoren ese orden sin gastar cómputo en combinaciones poco informativas?</p>

<p class="table-caption"><strong>Tabla 2</strong>: Dos ejercicios equivalentes para pensar HPO como problema de ranking</p>

<table>
  <thead>
    <tr>
      <th>Dimensión</th>
      <th>RSH, muestra pública</th>
      <th>Ecommerce, estilo Shopify</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Unidad de análisis</td>
      <td>Hogar</td>
      <td>Cliente, sesión, cliente-campaña o cliente-producto</td>
    </tr>
    <tr>
      <td>Pregunta sustantiva</td>
      <td>¿Qué hogares presentan mayor probabilidad relativa de vulnerabilidad, usando señales indirectas y no el ingreso como predictor?</td>
      <td>¿Qué clientes o sesiones deberían priorizarse porque concentran mayor probabilidad de compra, margen esperado o respuesta incremental a una acción comercial?</td>
    </tr>
    <tr>
      <td>Fuente</td>
      <td>Muestra pública, aleatoria y anonimizada del RSH disponible en <a href="https://bidat.gob.cl/details/ficha/dataset/registro-social-de-hogares-muestra-diciembre-2025">BIDAT</a></td>
      <td>Tabla propia de navegación, transacciones y campañas: sesiones, carritos, compras, margen, descuentos, recurrencia, stock, canales y dispositivos</td>
    </tr>
    <tr>
      <td>Target razonable</td>
      <td>Una señal de vulnerabilidad construida fuera del set de predictores. Puede ser binaria, ordinal o continua: pertenencia a un grupo de alta vulnerabilidad, transición posterior a mayor vulnerabilidad, índice externo de privación o tramo de referencia usado solo como etiqueta, no como predictor.</td>
      <td>Dos opciones distintas: propensión a comprar o valor esperado, si no hay experimento; uplift causal, si existe asignación aleatoria, grupo de control o diseño cuasi experimental defendible.</td>
    </tr>
    <tr>
      <td>Qué se excluye</td>
      <td>Ingreso directo y variables que sean copias operacionales del ingreso o del target. La idea no es reconstruir mecánicamente la CSE, sino evaluar cuánto ordenamiento se puede recuperar desde señales indirectas de vulnerabilidad.</td>
      <td>Variables posteriores a la intervención: apertura de campaña si se predice antes de enviarla, descuento efectivamente usado si se quiere decidir a quién ofrecerlo, compra observada dentro de la ventana objetivo, o cualquier variable contaminada por el resultado.</td>
    </tr>
    <tr>
      <td>Modelo propuesto</td>
      <td><strong>EBM</strong> con <code class="language-plaintext highlighter-rouge">interpretML</code>, porque permite revisar funciones parciales, monotonicidades plausibles, saltos extraños y efectos de interacción sin perder completamente el control interpretativo.</td>
      <td><strong>H2O XGBoost</strong>, porque es fuerte en tabular, maneja no linealidades e interacciones, escala bien y permite tratar el ecommerce como un problema operativo de ranking o valor esperado.</td>
    </tr>
    <tr>
      <td>Predictores plausibles</td>
      <td>Tamaño del hogar, composición etaria, presencia de niños, personas mayores o dependientes, escolaridad, ocupación, situación laboral, tenencia de vivienda, materialidad, hacinamiento, allegamiento, ruralidad, comuna o territorio agregado, acceso a servicios, discapacidad y otras señales socioeconómicas indirectas.</td>
      <td>Recencia, frecuencia, monto, margen, sesiones recientes, tiempo desde última compra, categorías visitadas, abandono de carrito, profundidad de navegación, sensibilidad histórica a descuentos, canal, device, fuente de adquisición, stock, estacionalidad, devoluciones y respuesta previa a campañas.</td>
    </tr>
    <tr>
      <td>Qué significa ordenar bien</td>
      <td>Que, al comparar dos hogares, el hogar más vulnerable según la señal de referencia tienda a recibir un score mayor. En la parte alta del ranking, debería concentrar hogares con mayor vulnerabilidad observada, sin depender de ingreso directo.</td>
      <td>Que el top k seleccionado concentre más compra, margen o efecto incremental que una priorización aleatoria o que una regla simple de negocio. Si hay experimento, importa el efecto incremental; si no lo hay, solo puede hablarse de propensión o valor esperado.</td>
    </tr>
    <tr>
      <td>Métricas principales</td>
      <td>AUC si el target es binario y el ranking global importa; AUCPR si la alta vulnerabilidad es minoritaria; NDCG@k o lift@k si importa el tramo superior; Kendall o Spearman si el target es ordinal; Brier y curvas de calibración si el score se interpretará como probabilidad.</td>
      <td>Para propensión: AUCPR, lift@k, gain@k y profit@k. Para valor esperado: RMSE, MAE, pinball loss o error ponderado por margen. Para uplift causal: uplift@k, Qini y ganancia incremental estimada en holdout experimental.</td>
    </tr>
    <tr>
      <td>Riesgo principal</td>
      <td>Circularidad, fuga de información y falsa legitimidad. Un modelo puede ordenar muy bien porque aprendió variables que son casi equivalentes al ingreso o al propio target. Eso sería buen desempeño aparente, pero mala evidencia.</td>
      <td>Confundir propensión con causalidad. Los mejores compradores no son necesariamente los más persuadibles. Un cupón enviado a quien habría comprado igual puede aumentar conversiones observadas y, al mismo tiempo, destruir margen incremental.</td>
    </tr>
  </tbody>
</table>

<h3 id="caso-rsh-ranking-de-vulnerabilidad-sin-usar-ingreso-directo">Caso RSH: ranking de vulnerabilidad sin usar ingreso directo</h3>

<p class="text-justify">El ejercicio RSH no debería formularse como “predecir pobreza” ni como “replicar la CSE”. Eso cerraría demasiado rápido la discusión y aumentaría el riesgo de circularidad. Lo más limpio es formularlo como un problema de <strong>ranking supervisado de vulnerabilidad relativa</strong>.</p>

<p class="text-justify">La función objetivo no busca solo acertar clases, sino mejorar la probabilidad de que el orden entre hogares sea correcto. Si el hogar $i$ es más vulnerable que el hogar $j$, el modelo debería asignar $s_i &gt; s_j$. Ese score puede calibrarse como probabilidad, pero su primer uso analítico es ordinal: ordenar hogares con la mayor estabilidad posible.</p>

<p class="text-justify">Una forma simple de escribirlo es:</p>

\[s_i = f_\theta(X_i), \quad X_i \not\ni ingreso\]

<p class="text-justify">donde $s_i$ es el score de vulnerabilidad del hogar, $X_i$ contiene señales indirectas y $\theta$ representa los hiperparámetros del modelo. El ingreso directo queda fuera de $X_i$. También deberían quedar fuera las variables que sean una copia administrativa demasiado cercana del target.</p>

<p class="text-justify">En un EBM, el score tiene una ventaja importante: puede descomponerse en efectos por variable e interacciones acotadas.</p>

\[g(E[y_i]) = \beta_0 + \sum_k f_k(x_{ik}) + \sum_{k&lt;l} f_{kl}(x_{ik}, x_{il})\]

<p class="text-justify">Esa forma no vuelve al modelo “justo” por sí misma, pero permite auditarlo mejor. Si el score aumenta de manera brusca en un punto absurdo de escolaridad, materialidad o composición del hogar, la forma funcional queda a la vista. En este caso, la interpretabilidad no es estética: es parte de la defensa metodológica del ranking.</p>

<p class="text-justify">Para HPO, un hiperparámetro ilustrativo es <span class="text-nowrap">max_bins</span>. Controla cuán finamente se discretizan las variables continuas antes de aprender efectos. Con pocos bins, el modelo puede suavizar demasiado y perder diferencias reales. Con demasiados bins, puede capturar ruido, producir saltos artificiales y empeorar la estabilidad del orden.</p>

<p class="text-justify">La comparación correcta no es “grilla versus Bayes” en abstracto. La comparación relevante es esta:</p>

<table>
  <thead>
    <tr>
      <th>Estrategia</th>
      <th>Qué haría con <span class="text-nowrap">max_bins</span></th>
      <th>Problema</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Grilla</td>
      <td>Probaría valores fijos, por ejemplo 32, 64, 128, 256, 512 y 1024.</td>
      <td>Ordenada, pero rígida. Si el buen rango está entre dos valores o depende de otro hiperparámetro, puede mirar mal.</td>
    </tr>
    <tr>
      <td>Random search</td>
      <td>Probaría valores aleatorios dentro de un rango.</td>
      <td>Es un baseline fuerte, pero no aprende explícitamente de los resultados anteriores.</td>
    </tr>
    <tr>
      <td>BO</td>
      <td>Usa los resultados ya observados para decidir el siguiente valor de <span class="text-nowrap">max_bins</span>.</td>
      <td>No garantiza el óptimo, pero puede ahorrar evaluaciones si la superficie tiene estructura aprovechable.</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">Un movimiento bivariado más realista sería optimizar <span class="text-nowrap">max_bins</span> junto con <span class="text-nowrap">interactions</span>. La intuición es clara: más granularidad en variables principales puede exigir más cautela con interacciones. Si se aumentan ambas sin control, el ranking puede mejorar en validación interna y empeorar fuera de muestra.</p>

\[\theta = (\mathrm{max\_bins},\ \mathrm{interactions})\]

<p class="text-justify">La métrica objetivo principal sería <strong>Kendall’s tau-b</strong>, porque el propósito del modelo no es solo clasificar hogares vulnerables, sino preservar correctamente la prelación entre ellos: que hogares con mayor vulnerabilidad de referencia reciban sistemáticamente scores más altos que hogares menos vulnerables. AUCPR puede reportarse como métrica complementaria si la alta vulnerabilidad se define como evento minoritario; NDCG@k, si interesa auditar especialmente el tramo superior del ranking; y Brier/calibración, solo si el score será interpretado como probabilidad. En una versión más exigente, además del desempeño global, exigiría estabilidad por subgrupos y territorio: un ranking que ordena bien solo en la región o tipo de hogar dominante no está listo para discusión pública sería según mi opinión.</p>

<h3 id="caso-ecommerce-lift-operativo-sin-confundirlo-con-causalidad">Caso ecommerce: lift operativo sin confundirlo con causalidad</h3>

<p class="text-justify">En ecommerce hay que separar tres modelos que suelen mezclarse:</p>

<ol>
  <li><strong>Propensión</strong>: probabilidad de compra futura.</li>
  <li><strong>Valor esperado</strong>: compra esperada ponderada por monto, margen o probabilidad de conversión.</li>
  <li><strong>Uplift causal</strong>: incremento atribuible a una acción, por ejemplo enviar un cupón, mostrar un banner o activar una recomendación.</li>
</ol>

<p class="text-justify">Si no hay experimento, y aquí entro en territorio desconocido para mi conocimiento, yo no prometería causalidad. Haría un modelo de propensión o de valor esperado y lo evaluaría como ranking comercial. Si hay experimento A/B o grupo de control válido, entonces sí se puede hablar de uplift más real: la pregunta pasa a ser quién compra más porque fue tratado, no simplemente quién iba a comprar de todos modos.</p>

<p class="text-justify">Usaría H2O XGBoost con dos variantes:</p>

<table>
  <thead>
    <tr>
      <th>Escenario</th>
      <th>Target</th>
      <th>Métrica</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sin experimento</td>
      <td>Compra futura, margen futuro o valor esperado en 7, 14 o 30 días</td>
      <td>AUCPR, lift@k, gain@k, profit@k, RMSE o MAE si el target es monto</td>
    </tr>
    <tr>
      <td>Con experimento</td>
      <td>Diferencia incremental atribuible al tratamiento</td>
      <td>uplift@k, Qini, ganancia incremental y validación contra holdout experimental</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">En el caso observacional, un score útil podría ser:</p>

\[score_i = \hat{p}_i(\text{compra}) \times \widehat{margen}_i\]

<p class="text-justify">Eso no mide causalidad, pero puede servir para priorizar acciones si el objetivo es eficiencia comercial. Si el costo del contacto o del descuento es conocido, conviene optimizar ganancia esperada:</p>

\[profit_i = \hat{p}_i(\text{compra}) \times \widehat{margen}_i - costo_i\]

<p class="text-justify">En H2O XGBoost, un hiperparámetro ilustrativo es <span class="text-nowrap">max_depth</span>. Controla la profundidad máxima de cada árbol. Con árboles muy superficiales, el modelo puede perder interacciones relevantes: por ejemplo, clientes recurrentes, con abandono reciente de carrito, alta sensibilidad a descuentos y stock disponible. Con árboles demasiado profundos, puede memorizar ruido de campañas, estacionalidad o eventos puntuales.</p>

<table>
  <thead>
    <tr>
      <th>Estrategia</th>
      <th>Qué haría con <span class="text-nowrap">max_depth</span></th>
      <th>Problema</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Grilla</td>
      <td>Probaría profundidades fijas, por ejemplo 2, 4, 6, 8, 10 y 12.</td>
      <td>Simple, pero se vuelve costosa al combinarse con <span class="text-nowrap">learn_rate</span>, <span class="text-nowrap">min_rows</span>, <span class="text-nowrap">sample_rate</span> y <span class="text-nowrap">col_sample_rate</span>.</td>
    </tr>
    <tr>
      <td>Random search</td>
      <td>Probaría profundidades aleatorias y combinaciones al azar de otros hiperparámetros.</td>
      <td>Buen baseline, especialmente si pocas dimensiones importan de verdad.</td>
    </tr>
    <tr>
      <td>BO</td>
      <td>Aprende desde los trials previos qué zonas producen mejor lift@k, profit@k o AUCPR, y decide dónde probar después.</td>
      <td>Depende de que la métrica sea estable y de que la validación represente el uso real del modelo.</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">El movimiento bivariado natural es <span class="text-nowrap">max_depth</span> con <span class="text-nowrap">min_rows</span> o <span class="text-nowrap">learn_rate</span>.</p>

\[\theta = (\mathrm{max\_depth},\; \mathrm{min\_rows})\]

<p class="text-justify">La intuición: si se permiten árboles más profundos, puede ser necesario exigir más observaciones mínimas por hoja para evitar reglas demasiado específicas. Otra dupla frecuente es <span class="text-nowrap">max_depth</span> con <span class="text-nowrap">learn_rate</span>: árboles más complejos con tasas de aprendizaje altas pueden sobreajustar rápido; tasas más bajas pueden necesitar más árboles y más tiempo.</p>

<p class="text-justify">Ahí BO tiene sentido práctico. No porque “Bayes sea mejor” por definición, sino porque una grilla cartesiana crece rápido. Si se prueban 8 valores de profundidad, 8 de <span class="text-nowrap">min_rows</span>, 6 de <span class="text-nowrap">learn_rate</span>, 5 de <span class="text-nowrap">sample_rate</span> y 5 de <span class="text-nowrap">col_sample_rate</span>, ya son 9.600 combinaciones antes de pensar en validación cruzada o ventanas temporales. Random search reduce el costo; BO intenta reducirlo aprendiendo de cada evaluación.</p>

<p class="text-justify">La idea de fondo para ambos ejemplos es la misma:</p>

\[\theta^* = \arg\max_{\theta \in \Theta} M(f_\theta, D_{valid})\]

<p class="text-justify">donde $M$ puede ser AUCPR, NDCG@k, lift@k, profit@k, Qini o una combinación penalizada por inestabilidad. BO no asume que los hiperparámetros tengan distribución normal. En su versión con procesos gaussianos, modela probabilísticamente la función objetivo: qué desempeño cabe esperar para una configuración todavía no evaluada, dado lo que ya se observó.</p>

<p class="text-justify">La decisión metodológica queda así: random search es el baseline mínimo; BO entra cuando cada entrenamiento cuesta, cuando el espacio de búsqueda es razonable y cuando la métrica de validación representa el uso real del modelo. Si esas tres condiciones no se cumplen, BO puede producir una optimización elegante sobre una pregunta mal planteada.</p>

<h2 id="cucharada-2-el-experimento-antes-que-el-algoritmo">Cucharada 2: el experimento antes que el algoritmo</h2>

<p class="text-justify">La optimización de hiperparámetros, creo yo, parte fijando como evaluaremos el éxito. En estos dos ejemplos, el contrato de éxito tendría seis piezas:</p>

<p class="table-caption"><strong>Tabla 3</strong>: Contrato mínimo antes de hacer HPO</p>

<table>
  <thead>
    <tr>
      <th>Decisión</th>
      <th>Qué debe quedar fijo</th>
      <th>Por qué importa</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Unidad</td>
      <td>Hogar, cliente, sesión o cliente-campaña</td>
      <td>Si la unidad cambia, cambia el target, la validación y la interpretación del score.</td>
    </tr>
    <tr>
      <td>Target</td>
      <td>Señal de vulnerabilidad, compra futura, margen esperado o efecto incremental</td>
      <td>No se optimiza lo mismo si el target es ordinal, binario, monetario o causal.</td>
    </tr>
    <tr>
      <td>Métrica principal</td>
      <td>Una métrica alineada con la decisión</td>
      <td>La métrica debe representar el uso real del ranking, no solo verse bien en un leaderboard.</td>
    </tr>
    <tr>
      <td>Split</td>
      <td>Validación fuera de muestra, idealmente temporal cuando corresponde</td>
      <td>El tuning contra una validación débil produce confianza artificial.</td>
    </tr>
    <tr>
      <td>Presupuesto</td>
      <td>Número máximo de entrenamientos</td>
      <td>HPO es una decisión bajo restricción de cómputo, no una búsqueda infinita.</td>
    </tr>
    <tr>
      <td>Baseline</td>
      <td>Regla simple y random search</td>
      <td>BO debe justificar su complejidad contra alternativas razonables.</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">La parte estadística clave es que la métrica observada no es la métrica verdadera. Cada trial entrega una estimación ruidosa del desempeño:</p>

\[\widehat{M}(\theta) = M(\theta) + \varepsilon\]

<p class="text-justify">Ese ruido aparece por splits, folds, prevalencia del evento, tamaño muestral, cambios temporales, subgrupos pequeños y variación propia del entrenamiento. En RSH puede verse como inestabilidad por territorio o tipo de hogar. En ecommerce puede verse como estacionalidad, campañas simultáneas, cambios de stock, descuentos o ventanas de validación poco representativas.</p>

<p class="text-justify">Por eso, en lugar de optimizar solo una métrica limpia, conviene optimizar una métrica penalizada:</p>

\[J(\theta) = M(\theta) - \lambda_1 \cdot \text{inestabilidad} - \lambda_2 \cdot \text{complejidad}\]

<p class="text-justify">La intuición es simple. Una configuración no debería ganar solo porque sube marginalmente la métrica principal. Debería ganar porque mejora el ranking (particularmente en RSH/SIVUST, donde el orden es lo crítico), se sostiene fuera de muestra y no introduce una complejidad difícil de defender.</p>

<p class="text-justify">En el caso RSH, esa función podría premiar Kendall’s tau-b y castigar inestabilidad por territorio, composición del hogar o subgrupos relevantes. En ecommerce, podría premiar profit@k o lift@k y castigar volatilidad temporal, exceso de profundidad o dependencia de una campaña puntual.</p>

<p class="text-justify">El espacio de búsqueda también debe pensarse, no solo declararse. Una grilla amplia puede parecer neutral, pero en realidad contiene supuestos. Decidir que <span class="text-nowrap">max_depth</span> va de 2 a 20, o que <span class="text-nowrap">max_bins</span> puede llegar a 4096, no es inocente. Amplía el espacio, encarece la búsqueda y permite configuraciones que quizá nunca deberían competir.</p>

<p class="text-justify">Una regla práctica:</p>

<p class="table-caption"><strong>Tabla 4</strong>: Cómo pensaría el espacio de búsqueda</p>

<table>
  <thead>
    <tr>
      <th>Tipo de hiperparámetro</th>
      <th>Tratamiento razonable</th>
      <th>Ejemplo</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Enteros de complejidad</td>
      <td>Rangos acotados y sustantivamente defendibles</td>
      <td><span class="text-nowrap">max_depth</span>, <span class="text-nowrap">max_bins</span>, <span class="text-nowrap">interactions</span></td>
    </tr>
    <tr>
      <td>Tasas o regularización</td>
      <td>Escala logarítmica</td>
      <td><span class="text-nowrap">learn_rate</span>, penalizaciones, regularización</td>
    </tr>
    <tr>
      <td>Muestreo</td>
      <td>Rangos conservadores</td>
      <td><span class="text-nowrap">sample_rate</span>, <span class="text-nowrap">col_sample_rate</span></td>
    </tr>
    <tr>
      <td>Parámetros condicionales</td>
      <td>Activarlos solo si corresponde</td>
      <td>Interacciones solo si el modelo base ya es estable</td>
    </tr>
    <tr>
      <td>Costo computacional</td>
      <td>Registrar tiempo por trial</td>
      <td>Un punto levemente mejor puede no justificar triplicar el costo</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">Aquí entra BO, pero con un rol acotado. No define el target, no corrige fugas/circularidad (“leakage” 🕶️) y no decide qué error es aceptable. La secuencia práctica sería esta:</p>

<ol>
  <li>correr una regla simple;</li>
  <li>correr random search con un presupuesto fijo;</li>
  <li>correr BO con el mismo presupuesto;</li>
  <li>comparar no solo la mejor métrica, sino la curva de aprendizaje;</li>
  <li>revisar estabilidad en test;</li>
  <li>publicar también los trials fallidos.</li>
</ol>

<p class="text-justify">La curva de aprendizaje importa mucho. Si BO supera a random search recién después de 300 trials, pero el presupuesto real era 30, no aportó. Si random search alcanza un resultado similar con menor complejidad, también es evidencia. La pregunta no es qué método tiene mejor reputación, sino cuál entrega mejor decisión con el presupuesto disponible.</p>

<p class="text-justify">Para este post, usaría <strong>Optuna</strong> como orquestador principal. No porque sea “más bayesiano” en abstracto, sino porque permite registrar estudios, reanudar trials, comparar samplers y guardar resultados (originalmente probé con otras librerías en SAT sin éxito, terminaba usando artefactor como pickle para suplir cosas que no tenía la librería). El motor de entrenamiento puede ser H2O XGBoost, EBM u otro modelo tabular; Optuna solo necesita una función objetivo que devuelva una métrica.</p>

<p class="text-justify">También distinguiría tres niveles de búsqueda:</p>

<p class="table-caption"><strong>Tabla 5</strong>: Tres niveles de búsqueda posibles</p>

<table>
  <thead>
    <tr>
      <th>Nivel</th>
      <th>Estrategia</th>
      <th>Uso razonable</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Base</td>
      <td>Random search</td>
      <td>Baseline técnico mínimo. Si BO no lo supera, no hay mucho que defender.</td>
    </tr>
    <tr>
      <td>Intermedio</td>
      <td>TPE o GP vía Optuna</td>
      <td>Buen equilibrio entre practicidad, trazabilidad y búsqueda secuencial.</td>
    </tr>
    <tr>
      <td>Avanzado</td>
      <td>SMAC, BoTorch o multiobjetivo</td>
      <td>Al parecer es útil si hay restricciones, objetivos múltiples o espacios condicionales complejos (NO LO HE PROBADO).</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">No sobredefendería el proceso gaussiano. Para explicar BO es útil, pero en espacios mixtos, discretos o condicionales, TPE o SMAC parecen ser más prácticos. En problemas pequeños y relativamente suaves, GP tiene sentido. En problemas grandes, con categorías, condicionalidad o ruido, conviene comparar. En resumen, hay que medir cuánto cuesta cada evaluación y qué inestabilidad no estamos dispuestos a aceptar.</p>

<hr />

<h2 id="cucharada-3-alternativas-y-cierre">Cucharada 3: Alternativas y cierre</h2>

<p class="text-justify">En lugar de BO o en su complemento, el uso de LLM puede entrar como una capa. Primero, antes del tuning, para proponer espacios de búsqueda razonables, detectar hiperparámetros mal escalados y sugerir restricciones. Segundo, durante el tuning, para leer trials fallidos y proponer ajustes al espacio. Tercero, después del tuning, para revisar consistencia: pérdida de información, variables sospechosas, métricas que no calzan con la decisión o explicaciones demasiado frágiles (HAY QUE EXPERIMENTAR).</p>

<p class="text-justify">El flujo más interesante sería híbrido:</p>

\[\text{conocimiento de dominio}
\rightarrow
\text{espacio de búsqueda}
\rightarrow
\text{random search}
\rightarrow
\text{BO}
\rightarrow
\text{auditoría}
\rightarrow
\text{rediseño}\]

<p class="text-justify">Y, en paralelo:</p>

\[\text{LLM}
\rightarrow
\text{mejores hipótesis de búsqueda}
\rightarrow
\text{menos trials absurdos}\]

<p class="text-justify">La gracia no es reemplazar Bayes por LLM ni LLM por Bayes. La gracia es que cada parte haga lo que sabe hacer mejor. El LLM puede ayudar a pensar, resumir, criticar y proponer. BO puede asignar mejor el presupuesto de evaluación. La validación, en cambio, sigue siendo el tribunal.</p>

<hr />

<h2 id="cierre-una-invitación-a-probar-con-datos-reales">Cierre: una invitación a probar con datos reales</h2>

<p class="text-justify">La pregunta que me interesa dejar abierta no es si BO es “mejor” que random search. Esa pregunta, así formulada, es demasiado amplia. La pregunta útil es más concreta:</p>

<p><strong>con 30 entrenamientos disponibles, ¿qué estrategia entrega el ranking más estable, defendible y útil?</strong></p>

<p class="text-justify">En RSH, eso significa probar si un modelo transparente puede ordenar vulnerabilidad relativa sin usar ingreso directo (por ausencia o fragilidad del dato directo), con auditoría por territorio y tipo de hogar. En ecommerce, significa probar si un modelo tabular optimizado mejora una regla simple de negocio en profit@k, lift@k o ganancia incremental, respetando ventanas temporales.</p>

<p class="text-justify">Considerar un set de estrategias:</p>

<table>
  <thead>
    <tr>
      <th>Estrategia</th>
      <th>Pregunta que responde</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Regla simple</td>
      <td>¿Cuánto aporta realmente el modelo?</td>
    </tr>
    <tr>
      <td>Random search</td>
      <td>¿Cuánto se gana con una búsqueda barata y honesta?</td>
    </tr>
    <tr>
      <td>BO</td>
      <td>¿Cuánto se gana aprendiendo del historial de trials?</td>
    </tr>
    <tr>
      <td>LLM + BO</td>
      <td>¿Cuánto se gana si el espacio de búsqueda parte mejor diseñado?</td>
    </tr>
  </tbody>
</table>

<p class="text-justify">Si alguien trabaja en política pública, me gustaría saber qué señales indirectas usan para ordenar sus modelos sin caer en circularidad. Si alguien trabaja en ecommerce u otra industria, cómo definen métricas cuando no hay experimento y cómo separan propensión de efecto incremental. Y si alguien ya usa LLM para diseñar búsquedas de hiperparámetros, feliz de leerlo 🤩.</p>

<p class="text-justify">La optimización de hiperparámetros no es el centro del problema. El centro es la decisión que viene después del ranking. En política pública, una mala prelación puede dañar legitimidad. En industrias, puede destruir margen. En ambos casos, ordenar bien importa más que declarar ganador a un algoritmo.</p>

<h2 id="referencias">Referencias</h2>

<ul>
  <li>Ament, Sebastian; Daulton, Samuel; Eriksson, David; Balandat, Maximilian; Bakshy, Eytan. <a href="https://arxiv.org/abs/2310.20708">Unexpected Improvements to Expected Improvement for Bayesian Optimization</a>, NeurIPS 2023.</li>
  <li>Balandat, Maximilian et al. <a href="https://arxiv.org/abs/1910.06403">BoTorch: A Framework for Efficient Monte-Carlo Bayesian Optimization</a>, NeurIPS 2020.</li>
  <li>Bergstra, James; Bengio, Yoshua. <a href="https://jmlr.org/papers/v13/bergstra12a.html">Random Search for Hyper-Parameter Optimization</a>, JMLR 2012.</li>
  <li>Bischl, Bernd et al. <a href="https://doi.org/10.1002/widm.1484">Hyperparameter Optimization: Foundations, Algorithms, Best Practices and Open Challenges</a>, WIREs Data Mining and Knowledge Discovery, 2023. Versión abierta en <a href="https://arxiv.org/abs/2107.05847">arXiv</a>.</li>
  <li>Caruana, Rich et al. <a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2017/06/KDD2015FinalDraftIntelligibleModels4HealthCare_igt143e-caruanaA.pdf">Intelligible Models for HealthCare: Predicting Pneumonia Risk and Hospital 30-day Readmission</a>, KDD 2015.</li>
  <li>H2O.ai. <a href="https://docs.h2o.ai/h2o/latest-stable/h2o-docs/grid-search.html">Grid (Hyperparameter) Search</a>, documentación oficial.</li>
  <li>H2O.ai. <a href="https://docs.h2o.ai/h2o/latest-stable/h2o-docs/data-science/xgboost.html">XGBoost</a>, documentación oficial.</li>
  <li>InterpretML. <a href="https://interpret.ml/docs/ebm.html">Explainable Boosting Machine</a> y <a href="https://interpret.ml/docs/hyperparameters.html">Hyperparameters</a>, documentación oficial.</li>
  <li>Lindauer, Marius; Eggensperger, Katharina; Feurer, Matthias; Biedenkapp, André; Deng, Difan; Benjamins, Carolin; Ruhkopf, Tim; Sass, René; Hutter, Frank. <a href="https://www.jmlr.org/papers/v23/21-0888.html">SMAC3: A Versatile Bayesian Optimization Package for Hyperparameter Optimization</a>, JMLR 2022.</li>
  <li>Liu, Tennison; Astorga, Nicolás; Seedat, Nabeel; van der Schaar, Mihaela. <a href="https://arxiv.org/abs/2402.03921">Large Language Models to Enhance Bayesian Optimization</a>, 2024.</li>
  <li>Ministerio de Desarrollo Social y Familia, BIDAT. <a href="https://bidat.gob.cl/details/ficha/dataset/registro-social-de-hogares-muestra-diciembre-2025">Registro Social de Hogares, Muestra diciembre 2025</a>, publicado el 30 de enero de 2026.</li>
  <li>Optuna. <a href="https://optuna.org/">Optuna: A Hyperparameter Optimization Framework</a> y <a href="https://optuna.readthedocs.io/en/stable/reference/samplers/generated/optuna.samplers.GPSampler.html"><code class="language-plaintext highlighter-rouge">GPSampler</code></a>, documentación oficial.</li>
  <li>Scikit-Optimize. <a href="https://scikit-optimize.github.io/stable/modules/generated/skopt.gp_minimize.html"><code class="language-plaintext highlighter-rouge">gp_minimize</code></a>, documentación oficial.</li>
  <li>Villagrán Prieto, Nicolás; Garrido-Merchán, Eduardo C. <a href="https://arxiv.org/abs/2602.08774">Default Machine Learning Hyperparameters Do Not Provide Informative Initialization for Bayesian Optimization</a>, 2026, preprint.</li>
  <li>Zhou, Han; Ma, Xingchen; Blaschko, Matthew B. <a href="https://arxiv.org/abs/2310.05166">A Corrected Expected Improvement Acquisition Function Under Noisy Observations</a>, 2023.</li>
</ul>]]></content><author><name>Cristián Labra Olivares</name></author><category term="mlops" /><category term="hpo" /><category term="python" /><category term="h2o" /><category term="bayesian-optimization" /><category term="hyperparameter-optimization" /><category term="h2o" /><category term="xgboost" /><category term="ebm" /><category term="rsh" /><category term="ecommerce" /><category term="aucpr" /><category term="reproducibilidad" /><summary type="html"><![CDATA[Guía directa para usar optimización bayesiana como estrategia de búsqueda de hiperparámetros en modelos predictivos: un caso público tipo RSH con EBM y un caso privado tipo ecommerce con H2O XGBoost.]]></summary></entry><entry xml:lang="es"><title type="html">CASEN 2024 en 3 cucharadas: sin lectura territorial a baja escala, la política social avanza a ciegas</title><link href="https://3cucharadas.cl/datos/politica-publica/julia/casen/casen2024-julia-waffles-politica-publica/" rel="alternate" type="text/html" title="CASEN 2024 en 3 cucharadas: sin lectura territorial a baja escala, la política social avanza a ciegas" /><published>2026-03-15T00:00:00-03:00</published><updated>2026-03-15T00:00:00-03:00</updated><id>https://3cucharadas.cl/datos/politica-publica/julia/casen/casen2024-julia-waffles-politica-publica</id><content type="html" xml:base="https://3cucharadas.cl/datos/politica-publica/julia/casen/casen2024-julia-waffles-politica-publica/"><![CDATA[<p>En Chile, <strong>La Araucanía registra 13.0% de pobreza extrema; Magallanes, 4.2%</strong>. Son 8.8 puntos porcentuales de diferencia — y si un servicio público de nivel central o local (GOREs/Municipios) diseñan su intervención usando solo el promedio nacional (6.9%), o despreciando las diferencias regionales, podrían equivocarse en asignar recursos o distribuir sus componentes.</p>

<p>Este post documenta un análisis reproducible de CASEN 2024 en <a href="https://julialang.org">Julia</a>, con validación cruzada de cifras oficiales públicas en BIDAT y buena trazabilidad  del flujo en la repo.</p>

<p><strong>Tres hallazgos para comenzar — estadísticamente robustos:</strong></p>

<ul>
  <li><strong>Pobreza extrema</strong>: La Araucanía 13.0% IC 95 % [11.8%, 14.1%] versus Magallanes 4.2% [3.1%, 5.2%] — brecha de <strong>8.8 pp con CIs no superpuestos</strong>.</li>
  <li><strong>Cobertura FONASA</strong>: La Araucanía 91.1% [90.2%, 92.0%] versus Metropolitana 75.9% [75.0%, 76.7%] — brecha de <strong>15.2 pp con CIs no superpuestos</strong>.</li>
  <li><strong>Educación superior completa</strong>: Metropolitana 34.9% [34.0%, 35.7%] versus Maule 20.4% [19.2%, 21.6%] — brecha de <strong>14.5 pp con CIs no superpuestos</strong>.</li>
</ul>

<p>Los IC son del 95 % y fueron calculados por <strong>Taylor linearization</strong> (<a href="https://en.wikipedia.org/wiki/Linearization">wiki</a>) para el diseño muestral complejo de CASEN (estratificado bietápico, ponderadores <code class="language-plaintext highlighter-rouge">expr</code>). Que los CIs no se superpongan implica que estas diferencias regionales son estadísticamente significativas al nivel convencional.</p>

<hr />

<h2 id="tolerancia-al-contraste-o-cotejo-con-datos-oficiales">Tolerancia al contraste o cotejo con datos oficiales</h2>

<p>Todos los resultados fueron contrastados contra las tablas oficiales disponibles en <a href="https://bidat.gob.cl/url/695ff7271b10e">BIDAT</a>.</p>

<p class="table-caption"><strong>Tabla 1</strong> — Resultados de validación oficial (BIDAT, CASEN 2024)</p>

<table>
  <thead>
    <tr>
      <th>Parámetro</th>
      <th>Valor</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Estado validación (nacional + regional, % + expandidos)</td>
      <td><strong>PASA</strong></td>
    </tr>
    <tr>
      <td>Tolerancia máxima en puntos porcentuales</td>
      <td>1×10⁻⁵ pp</td>
    </tr>
    <tr>
      <td>Tolerancia máxima en valores expandidos</td>
      <td>1×10⁻⁶</td>
    </tr>
    <tr>
      <td>Diferencia observada (pp)</td>
      <td>2.98×10⁻⁶ pp</td>
    </tr>
    <tr>
      <td>Diferencia observada (expandido)</td>
      <td>0.0</td>
    </tr>
    <tr>
      <td>Filas comparadas nacional</td>
      <td>16</td>
    </tr>
    <tr>
      <td>Filas comparadas regional</td>
      <td>256</td>
    </tr>
  </tbody>
</table>

<p>La diferencia máxima observada es inferior a 3 millonésimas de punto porcentual, tolerable 😀. <strong>Los resultados son numéricamente idénticos a los oficiales.</strong></p>

<hr />

<h2 id="cucharada-1-diseño-muestral-y-expansión-sin-atajos">Cucharada 1: diseño muestral y expansión sin atajos</h2>

<p>CASEN 2024 tiene diseño <strong>estratificado bietápico probabilístico</strong> (<a href="https://bidat.gob.cl/url/69b71c77197db">nota metodológica BIDAT</a>). Para estimaciones a nivel regional, el factor correcto es <code class="language-plaintext highlighter-rouge">expr</code>; para nivel comunal se requiere <code class="language-plaintext highlighter-rouge">expc</code> — no son intercambiables. Este análisis usa <code class="language-plaintext highlighter-rouge">expr</code> y reporta estimaciones por región con IC 95 % calculados por <strong>Taylor linearization</strong> sobre el diseño complejo (estratos, UPM/PSU y pesos/factores).</p>

<p>Población representada en esta ejecución (suma de <code class="language-plaintext highlighter-rouge">expr</code>): <strong>20.13 millones de personas</strong> (un trabajo pendiente es evaluar el impacto de nuevo Censo 2024 en lugar de proyecciones sobre Censo 2017).</p>

<div class="language-julia highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Especificación del diseño muestral CASEN 2024</span>
<span class="n">design</span> <span class="o">=</span> <span class="x">(</span>
    <span class="n">weight</span> <span class="o">=</span> <span class="o">:</span><span class="n">expr</span><span class="x">,</span>     <span class="c"># factor de expansión regional</span>
    <span class="n">strata</span> <span class="o">=</span> <span class="o">:</span><span class="n">estrato</span><span class="x">,</span>  <span class="c"># estrato de muestreo</span>
    <span class="n">psu</span>    <span class="o">=</span> <span class="o">:</span><span class="n">cod_upm</span><span class="x">,</span>  <span class="c"># unidad primaria de muestreo (UPM)</span>
    <span class="n">domain</span> <span class="o">=</span> <span class="o">:</span><span class="n">region</span><span class="x">,</span>   <span class="c"># dominio de estimación</span>
<span class="x">)</span>
</code></pre></div></div>

<p>Cobertura por dimensión analizada:</p>

<p class="table-caption"><strong>Tabla 2</strong> — Variables CASEN 2024 utilizadas y población objetivo</p>

<table>
  <thead>
    <tr>
      <th>Dimensión</th>
      <th>Variable CASEN</th>
      <th>Población objetivo</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Educación</td>
      <td><code class="language-plaintext highlighter-rouge">educc</code></td>
      <td>Personas ≥ 18 años</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td><code class="language-plaintext highlighter-rouge">s13</code></td>
      <td>Población total</td>
    </tr>
    <tr>
      <td>Pobreza</td>
      <td><code class="language-plaintext highlighter-rouge">pobreza</code></td>
      <td>Población total</td>
    </tr>
  </tbody>
</table>

<h3 id="resultados-nacionales-ponderados">Resultados nacionales ponderados</h3>

<p>Los porcentajes siguientes corresponden a proporciones ponderadas con <code class="language-plaintext highlighter-rouge">expr</code>, validadas contra datos oficiales en BIDAT. La diferencia con los valores oficiales es &lt; 3×10⁻⁶ pp.</p>

<p class="table-caption"><strong>Tabla 3</strong> — Distribución nacional ponderada (CASEN 2024, principales categorías)</p>

<table>
  <thead>
    <tr>
      <th>Dimensión</th>
      <th>Categoría</th>
      <th style="text-align: center">% nacional</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Educación</td>
      <td>Media Completa</td>
      <td style="text-align: center">30.9%</td>
    </tr>
    <tr>
      <td>Educación</td>
      <td>Superior Completa</td>
      <td style="text-align: center">29.1%</td>
    </tr>
    <tr>
      <td>Educación</td>
      <td>Superior Incompleta</td>
      <td style="text-align: center">12.5%</td>
    </tr>
    <tr>
      <td>Educación</td>
      <td>Media Incompleta</td>
      <td style="text-align: center">9.9%</td>
    </tr>
    <tr>
      <td>Educación</td>
      <td>Básica Incompleta</td>
      <td style="text-align: center">8.4%</td>
    </tr>
    <tr>
      <td>Educación</td>
      <td>Otros</td>
      <td style="text-align: center">7.7%</td>
    </tr>
    <tr>
      <td>Educación</td>
      <td>Sin Educ. Formal</td>
      <td style="text-align: center">1.5%</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>Sistema Público FONASA</td>
      <td style="text-align: center">82.6%</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>Isapre</td>
      <td style="text-align: center">13.2%</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>Ninguno (particular)</td>
      <td style="text-align: center">2.0%</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>FF.AA. y del Orden</td>
      <td style="text-align: center">1.8%</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>No sabe</td>
      <td style="text-align: center">0.3%</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>Otro sistema</td>
      <td style="text-align: center">0.2%</td>
    </tr>
    <tr>
      <td>Pobreza</td>
      <td>No pobreza</td>
      <td style="text-align: center">82.7%</td>
    </tr>
    <tr>
      <td>Pobreza</td>
      <td>Pobreza no extrema</td>
      <td style="text-align: center">10.4%</td>
    </tr>
    <tr>
      <td>Pobreza</td>
      <td>Pobreza extrema</td>
      <td style="text-align: center">6.9%</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="cucharada-2-el-flujo-técnico-en-julia">Cucharada 2: el flujo técnico en Julia</h2>

<p>El pipeline corre de punta a punta con <code class="language-plaintext highlighter-rouge">julia --project=. scripts/run_all.jl</code> (orquestador). Las dos piezas de código más relevantes para reproducir y “auditar” estos resultados son el algoritmo de asignación de celdas y la especificación del diseño muestral (ambos en el repositorio de gitlab/github).</p>

<h3 id="taylor-linearization-se-e-ic-del-diseño-complejo">Taylor linearization: SE e IC del diseño complejo</h3>

<p>Se implementó el estimador de Taylor para proporciones en dominios (regiones). La variable linearizada para la proporción $\hat{p}_d$ en dominio $d$ es:</p>

\[z_j = \frac{1(j \in d)\,(1(\text{cat}_j = C) - \hat{p}_d)}{\hat{N}_d}\]

<p>La varianza se estima con la fórmula del diseño estratificado por conglomerados:</p>

<div class="language-julia highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Varianza Taylor linearization (estratificado, PSU)</span>
<span class="c"># e_{hi} = suma de w_j * z_j por PSU i en estrato h</span>
<span class="n">var_total</span> <span class="o">=</span> <span class="n">sum</span> <span class="n">over</span> <span class="n">strata</span> <span class="n">h</span><span class="o">:</span>
    <span class="x">(</span><span class="n">n_h</span> <span class="o">/</span> <span class="x">(</span><span class="n">n_h</span> <span class="o">-</span> <span class="mi">1</span><span class="x">))</span> <span class="o">*</span> <span class="n">sum_i</span> <span class="x">(</span><span class="n">e_</span><span class="x">{</span><span class="n">hi</span><span class="x">}</span> <span class="o">-</span> <span class="n">mean</span><span class="x">(</span><span class="n">e_h</span><span class="x">))</span><span class="o">^</span><span class="mi">2</span>

<span class="n">se</span>    <span class="o">=</span> <span class="n">sqrt</span><span class="x">(</span><span class="n">var_total</span><span class="x">)</span>
<span class="n">ci_lo</span> <span class="o">=</span> <span class="n">clamp</span><span class="x">(</span><span class="n">p̂</span> <span class="o">-</span> <span class="mf">1.96</span> <span class="o">*</span> <span class="n">se</span><span class="x">,</span> <span class="mf">0.0</span><span class="x">,</span> <span class="mf">1.0</span><span class="x">)</span>
<span class="n">ci_hi</span> <span class="o">=</span> <span class="n">clamp</span><span class="x">(</span><span class="n">p̂</span> <span class="o">+</span> <span class="mf">1.96</span> <span class="o">*</span> <span class="n">se</span><span class="x">,</span> <span class="mf">0.0</span><span class="x">,</span> <span class="mf">1.0</span><span class="x">)</span>
</code></pre></div></div>

<p>Se usan todos los PSU del diseño (incluidos los fuera del dominio, con $z_j = 0$), lo que es correcto para estimación de dominio aleatorio. El SE mediano regional es <strong>1.66 pp</strong> de ancho de IC; el máximo es <strong>5.76 pp</strong> (regiones pequeñas con categorías de baja prevalencia).</p>

<blockquote>
  <p><strong>Próxima entrada, en algún momento 👀 — Jackknife y Bootstrap para CASEN como contraste:</strong> TSL es una aproximación de primer orden óptima para medias y proporciones, pero para estadísticos no lineales (Gini, medianas, razones de cuantiles) puede sub-estimar la varianza. El <a href="https://github.com/tatanlabra/casen24_julia_viz/blob/main/docs/ic-varianza-casen.md">repositorio de código</a> incluye la teoría y el código Julia en desarrollo para contrastar TSL con Jackknife (delete-1) y Bootstrap — entrada futura de esta serie, no lo he revisado en profundidad.</p>
</blockquote>

<h3 id="resto-mayor-o-largest-remainder-por-qué-importa-en-un-waffle-chart">Resto Mayor o “Largest remainder”: por qué importa en un waffle chart</h3>

<p>Un waffle chart de 100 celdas exige que las proporciones sumen exactamente 100 enteros. El redondeo directo introduce errores acumulados que hacen que la suma sea 99 o 101. Este flujo usa el algoritmo de <strong>largest remainder</strong>, que garantiza la suma exacta introduciendo una imprecisión en post de la visualización (tomenlo como una choreza visual solamente):</p>

<div class="language-julia highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"""
Asigna `n_cells` celdas enteras a proporciones `p` usando largest-remainder.
Garantiza que sum(cells) == n_cells exactamente.
"""</span>
<span class="k">function</span><span class="nf"> allocate_cells</span><span class="x">(</span><span class="n">p</span><span class="o">::</span><span class="kt">AbstractVector</span><span class="x">{</span><span class="o">&lt;:</span><span class="kt">Real</span><span class="x">},</span> <span class="n">n_cells</span><span class="o">::</span><span class="kt">Int</span> <span class="o">=</span> <span class="mi">100</span><span class="x">)</span>
    <span class="n">raw</span>    <span class="o">=</span> <span class="n">p</span> <span class="o">.*</span> <span class="n">n_cells</span>
    <span class="n">floors</span> <span class="o">=</span> <span class="n">floor</span><span class="o">.</span><span class="x">(</span><span class="kt">Int</span><span class="x">,</span> <span class="n">raw</span><span class="x">)</span>
    <span class="n">remain</span> <span class="o">=</span> <span class="n">raw</span> <span class="o">.-</span> <span class="n">floors</span>
    <span class="n">deficit</span> <span class="o">=</span> <span class="n">n_cells</span> <span class="o">-</span> <span class="n">sum</span><span class="x">(</span><span class="n">floors</span><span class="x">)</span>
    <span class="c"># Asigna celdas restantes a las proporciones con mayor remainder</span>
    <span class="n">idx</span> <span class="o">=</span> <span class="n">sortperm</span><span class="x">(</span><span class="n">remain</span><span class="x">,</span> <span class="n">rev</span><span class="o">=</span><span class="nb">true</span><span class="x">)[</span><span class="mi">1</span><span class="o">:</span><span class="n">deficit</span><span class="x">]</span>
    <span class="n">floors</span><span class="x">[</span><span class="n">idx</span><span class="x">]</span> <span class="o">.+=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">floors</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Validado con tests unitarios: <code class="language-plaintext highlighter-rouge">allocate_cells([0.5, 0.3, 0.2], 100) == [50, 30, 20]</code>.</p>

<h3 id="reproducibilidad">Reproducibilidad</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Requisitos: Julia 1.10+</span>
git clone &lt;repo&gt;
<span class="nb">cd </span>casen2024/julia_viz
julia <span class="nt">--project</span><span class="o">=</span><span class="nb">.</span> <span class="nt">-e</span> <span class="s2">"using Pkg; Pkg.instantiate()"</span>
julia <span class="nt">--project</span><span class="o">=</span><span class="nb">.</span> scripts/run_all.jl
</code></pre></div></div>

<p>El flujo genera hartos elementos (tablas CSV, gráficos PNG, logs de auditoría de cada insumo). El archivo <code class="language-plaintext highlighter-rouge">Manifest.toml</code> fija las versiones exactas de todas las dependencias (ocupé Julia 1.10).</p>

<hr />

<h2 id="cucharada-3-evidencia-visual">Cucharada 3: evidencia visual</h2>

<h3 id="composición-nacional-gráficos-13">Composición nacional (Gráficos 1–3)</h3>

<p>Cada waffle representa 100 celdas asignadas por “largest remainder” sobre las proporciones ponderadas.</p>

<figure class="third ">
  
    
      <a href="/assets/images/casen2024-julia-waffles-politica-publica/waffle_educacion_educc.png" title="Gráfico 1 — Educación: nivel educacional alcanzado (población ≥18 años, CASEN 2024)">
          <img src="/assets/images/casen2024-julia-waffles-politica-publica/waffle_educacion_educc.png" alt="Gráfico 1: Distribución del nivel educacional alcanzado en la población adulta (≥18 años), Chile, CASEN 2024. Waffle chart de 100 celdas con proporciones por largest remainder." />
      </a>
    
  
    
      <a href="/assets/images/casen2024-julia-waffles-politica-publica/waffle_salud_s13.png" title="Gráfico 2 — Salud: sistema previsional de salud (población total, CASEN 2024)">
          <img src="/assets/images/casen2024-julia-waffles-politica-publica/waffle_salud_s13.png" alt="Gráfico 2: Distribución del sistema previsional de salud al que pertenece la población, Chile, CASEN 2024. Waffle chart con 6 categorías incluyendo FONASA, Isapre y otros." />
      </a>
    
  
    
      <a href="/assets/images/casen2024-julia-waffles-politica-publica/waffle_trabajo_ingresos_pobreza.png" title="Gráfico 3 — Pobreza por ingresos: extrema, no extrema y no pobreza (población total, CASEN 2024)">
          <img src="/assets/images/casen2024-julia-waffles-politica-publica/waffle_trabajo_ingresos_pobreza.png" alt="Gráfico 3: Situación de pobreza por ingresos en Chile según CASEN 2024: pobreza extrema, pobreza no extrema y no pobreza. Waffle chart de 100 celdas." />
      </a>
    
  
  
    <figcaption><strong>Gráficos 1–3</strong> — Composición nacional: educación (población ≥18 años), salud y pobreza (población total). Fuente: CASEN 2024, elaboración propia en Julia. Los valores están validados contra BIDAT. Clic para ampliar.
</figcaption>
  
</figure>

<h3 id="brechas-regionales-gráficos-46">Brechas regionales (Gráficos 4–6)</h3>

<p>Cada panel usa un <strong>eje ajustado al rango de su propia categoría</strong> (no escala global compartida), lo que permite visualizar diferencias que se aplanan si todas las categorías comparten el mismo eje. Las <strong>barras horizontales</strong> son IC 95 % calculados por Taylor linearization. El punto vacío (○) marca la referencia nacional en cada panel (con su CI).</p>

<figure class="third ">
  
    
      <a href="/assets/images/casen2024-julia-waffles-politica-publica/regional_dotplot_educacion_educc.png" title="Gráfico 4 — Brechas regionales en educación: dot plot por categoría (eje ajustado por panel, punto vacío = referencia nacional)">
          <img src="/assets/images/casen2024-julia-waffles-politica-publica/regional_dotplot_educacion_educc.png" alt="Gráfico 4: Dot plot de brechas regionales en nivel educacional por categoría, CASEN 2024. Cada panel tiene eje ajustado a su rango; punto vacío indica referencia nacional." />
      </a>
    
  
    
      <a href="/assets/images/casen2024-julia-waffles-politica-publica/regional_dotplot_salud_s13.png" title="Gráfico 5 — Brechas regionales en salud: dot plot por categoría (eje ajustado por panel, punto vacío = referencia nacional)">
          <img src="/assets/images/casen2024-julia-waffles-politica-publica/regional_dotplot_salud_s13.png" alt="Gráfico 5: Dot plot de brechas regionales en sistema previsional de salud por categoría, CASEN 2024. Eje ajustado por panel con referencia nacional." />
      </a>
    
  
    
      <a href="/assets/images/casen2024-julia-waffles-politica-publica/regional_dotplot_trabajo_ingresos_pobreza.png" title="Gráfico 6 — Brechas regionales en pobreza: dot plot (eje ajustado por panel, punto vacío = referencia nacional)">
          <img src="/assets/images/casen2024-julia-waffles-politica-publica/regional_dotplot_trabajo_ingresos_pobreza.png" alt="Gráfico 6: Dot plot de brechas regionales en pobreza por ingresos, CASEN 2024. Eje ajustado por panel con referencia nacional." />
      </a>
    
  
  
    <figcaption><strong>Gráficos 4–6</strong> — Brechas regionales con IC 95 % (Taylor linearization, diseño complejo): educación, salud y pobreza. Barras = IC 95 %; punto vacío (○) = referencia nacional. Eje ajustado por categoría. Clic para ampliar.
</figcaption>
  
</figure>

<h3 id="brechas-con-ic-95---todas-estadísticamente-robustas">Brechas con IC 95 % — todas estadísticamente robustas</h3>

<p class="table-caption"><strong>Tabla 4</strong> — Brechas regionales con IC 95 % por Taylor linearization (CASEN 2024)</p>

<table>
  <thead>
    <tr>
      <th>Dimensión</th>
      <th>Categoría</th>
      <th style="text-align: center">Brecha (pp)</th>
      <th>Máximo</th>
      <th>IC 95 %</th>
      <th>Mínimo</th>
      <th>IC 95 %</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Pobreza</td>
      <td>No pobreza</td>
      <td style="text-align: center"><strong>18.6 pp</strong></td>
      <td>Magallanes 90.0%</td>
      <td>[88.5%, 91.5%]</td>
      <td>La Araucanía 71.4%</td>
      <td>[69.8%, 73.0%]</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>Isapre</td>
      <td style="text-align: center"><strong>16.3 pp</strong></td>
      <td>Metropolitana 20.6%</td>
      <td>[19.8%, 21.5%]</td>
      <td>Maule 4.3%</td>
      <td>[3.7%, 5.0%]</td>
    </tr>
    <tr>
      <td>Salud</td>
      <td>FONASA</td>
      <td style="text-align: center"><strong>15.2 pp</strong></td>
      <td>La Araucanía 91.1%</td>
      <td>[90.2%, 92.0%]</td>
      <td>Metropolitana 75.9%</td>
      <td>[75.0%, 76.7%]</td>
    </tr>
    <tr>
      <td>Educación</td>
      <td>Superior Completa</td>
      <td style="text-align: center"><strong>14.5 pp</strong></td>
      <td>Metropolitana 34.9%</td>
      <td>[34.0%, 35.7%]</td>
      <td>Maule 20.4%</td>
      <td>[19.2%, 21.6%]</td>
    </tr>
    <tr>
      <td>Pobreza</td>
      <td>Pobreza extrema</td>
      <td style="text-align: center"><strong>8.8 pp</strong></td>
      <td>La Araucanía 13.0%</td>
      <td>[11.8%, 14.1%]</td>
      <td>Magallanes 4.2%</td>
      <td>[3.1%, 5.2%]</td>
    </tr>
  </tbody>
</table>

<p>En todos los casos los IC no se superponen: las brechas son estadísticamente significativas al 5 %. IC calculados por Taylor linearization sobre diseño complejo (estratos, UPM/PSU, <code class="language-plaintext highlighter-rouge">expr</code>).</p>

<hr />

<h2 id="cierre-tres-preguntas-para-quienes-usan-la-encuesta">Cierre: tres preguntas para quienes usan la encuesta</h2>

<p>Si usas CASEN 2024 para caracterización territorial u otros usos donde variables a nivel regional son relevantes, piensalo dos veces antes de usar un dato puntual (sin su intervalo de confianza):</p>

<ol>
  <li><strong>¿Tus resultados están validados contra BIDAT y tienen IC de diseño?</strong> Una diferencia de más de 1×10⁻⁵ pp respecto a las tablas oficiales no es técnica: es de proceso. Y sin IC de diseño complejo, una brecha de 8 pp puede parecer evidencia cuando es ruido en regiones pequeñas.</li>
  <li><strong>¿Estás usando el factor de expansión correcto?</strong> <code class="language-plaintext highlighter-rouge">expr</code> es el apropiado para región; <code class="language-plaintext highlighter-rouge">expc</code> para comuna. No son intercambiables y usar el incorrecto sesga las estimaciones de cobertura.</li>
  <li><strong>¿Tu análisis es reproducible?</strong> Un flujo que no puede ser auditado no puede ser defendido frente a una contraparte técnica ni actualizado cuando salga CASEN 2026.</li>
</ol>

<p>Los IC aquí incorporados son de diseño complejo (Taylor linearization), no asintóticos simples. Cubren la varianza de muestreo pero no el error de no respuesta ni la subcobertura. Para inferencia causal entre subpoblaciones se requiere diseño adicional.</p>]]></content><author><name>Cristián Labra Olivares</name></author><category term="datos" /><category term="politica-publica" /><category term="julia" /><category term="casen" /><category term="casen2024" /><category term="julia" /><category term="expansion" /><category term="diseno-muestral" /><category term="waffle" /><category term="dotplot" /><category term="politica-publica" /><category term="bidat" /><category term="brecha-territorial" /><summary type="html"><![CDATA[Análisis reproducible de CASEN 2024 en Julia: validación oficial con datos en el BIDAT, composición nacional por waffle chart y brechas regionales en educación, salud y pobreza para priorización territorial.]]></summary></entry></feed>