<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Sandro Gomez’s personal blog]]></title><description><![CDATA[Experienced in Digital Transformation, Software Engineering, Agile methodologies, and innovation, with a focus on driving technological progress.

]]></description><link>https://sandrogomez.com</link><image><url>https://substackcdn.com/image/fetch/$s_!HyBY!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1774699-244a-4730-9a6b-884f9617cfae_144x144.png</url><title>Sandro Gomez’s personal blog</title><link>https://sandrogomez.com</link></image><generator>Substack</generator><lastBuildDate>Thu, 16 Apr 2026 15:48:17 GMT</lastBuildDate><atom:link href="https://sandrogomez.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Sandro Gomez]]></copyright><language><![CDATA[es]]></language><webMaster><![CDATA[sandrogomez@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[sandrogomez@substack.com]]></itunes:email><itunes:name><![CDATA[Sandro Gomez]]></itunes:name></itunes:owner><itunes:author><![CDATA[Sandro Gomez]]></itunes:author><googleplay:owner><![CDATA[sandrogomez@substack.com]]></googleplay:owner><googleplay:email><![CDATA[sandrogomez@substack.com]]></googleplay:email><googleplay:author><![CDATA[Sandro Gomez]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Mi stack de IA para desarrollo en 2026: Claude Code + Cowork + GitHub Copilot Agents]]></title><description><![CDATA[C&#243;mo arm&#233; un workflow donde cada herramienta tiene su rol, no compiten entre s&#237;, y juntas me dan el boost que necesito.]]></description><link>https://sandrogomez.com/p/mi-stack-de-ia-para-desarrollo-en</link><guid isPermaLink="false">https://sandrogomez.com/p/mi-stack-de-ia-para-desarrollo-en</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Sun, 05 Apr 2026 00:53:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HyBY!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1774699-244a-4730-9a6b-884f9617cfae_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>El problema: tratar todas las herramientas como chatbots</h2><p>Conozco a muchos devs que usan UNA herramienta de IA y la tratan como un chatbot glorificado. Le piden todo al mismo lugar &#8212; desde autocompletar una l&#237;nea hasta razonar sobre arquitectura &#8212; y despu&#233;s reclaman que &#8220;la IA no sirve para cosas complejas.&#8221;</p><p>La verdad es que estas herramientas no son intercambiables. Tienen fortalezas distintas, operan en capas distintas del trabajo, y cuando las combinas bien, el resultado es exponencial.</p><p>Despu&#233;s de varias semanas (y cometiendo varios errores), llegu&#233; a un setup que quiero compartir paso a paso.</p><div><hr></div><h2>Las tres capas del workflow</h2><p>Antes de meternos en la configuraci&#243;n, hay que entender el modelo mental:</p><p>&#129504; <strong>Pensar &#8594; Claude Code.</strong> Arquitectura, dise&#241;o de sistemas, razonamiento complejo, debugging cross-service. Ahora con subagentes nombrados, hooks, Computer Use y contexto de hasta 1M de tokens con Opus 4.6.</p><blockquote><p><strong>Bonus: </strong>Cuando inicio desde cero o bien hay un t&#243;pico en el cual no me siento muy c&#243;modo. Siempre inicio con <strong>Deep Research</strong>  de <strong>Gemini </strong>si cuento con fuentes las ordeno y proceso inicialmente en NotebookLM.</p></blockquote><p>&#128295; <strong>Ejecutar &#8594; GitHub Copilot (Editor + Cloud Agent).</strong> Completar c&#243;digo, refactors multi-archivo, issues convertidos en PRs de forma aut&#243;noma. Desde abril 2026, el Cloud Agent puede investigar y planificar sin abrir un PR, y t&#250; eliges el modelo que usa.</p><p>&#9889; <strong>Orquestar &#8594; Claude Cowork.</strong> Research, documentos, datos, organizaci&#243;n de archivos. Con Dispatch puedes asignar tareas desde el celular. Con Computer Use, Claude literalmente usa tu computador. Con Scheduled Tasks, todo esto corre en autom&#225;tico. </p><p><strong>NOTA: </strong>Si no te sientes c&#243;modo dando demasiados permisos, siempre puedes configurar o ejecutar en una maquina virtual.</p><p>La clave: cada herramienta opera en su capa sin pisarse. Cuando intentas que una haga el trabajo de otra, los resultados bajan.</p><div><hr></div><h2>Paso 1: Configurar Claude Code como tu arquitecto</h2><p><strong>Qu&#233; es</strong></p><p>Claude Code es una herramienta de terminal que te da un agente con acceso completo a tu codebase. No es un autocompletador &#8212; es un razonador que entiende el contexto completo de tu proyecto. Mientras escribo este post Claude Code es una plataforma ag&#233;ntica completa: subagentes, hooks, plugins, Computer Use, Dispatch, y soporte para contexto de 1M de tokens con Opus 4.6. Siempre puedes usar Sonnet 4.6. </p><p><strong>Instalaci&#243;n (Mac)</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;f28b8827-0ee5-4ef2-bc27-362cb972978b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">$ brew install --cask claude-code

# Iniciar en tu proyecto
cd tu-proyecto
claude</code></pre></div><p><strong>Configuraci&#243;n clave: los archivos de agente</strong></p><p>Ac&#225; es donde Claude Code se pone realmente poderoso. Puedes definir agentes especializados con archivos <code>.md</code> que act&#250;an como profesionales con expertise espec&#237;fica. Los subagentes nombrados aparecen en el typeahead de <code>@</code> &#8212; los invocas como mencionar&#237;as a alguien en Slack:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;5dde5e09-ef05-41f8-bd43-0f53ae07c583&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">.claude/
&#9500;&#9472;&#9472; settings.json
&#9500;&#9472;&#9472; commands/
&#9474;   &#9500;&#9472;&#9472; architect.md       # Agente de arquitectura
&#9474;   &#9500;&#9472;&#9472; security-audit.md  # Auditor de seguridad
&#9474;   &#9500;&#9472;&#9472; db-reviewer.md     # Revisor de modelos y migraciones
&#9474;   &#9492;&#9472;&#9472; test-strategist.md # Estratega de testing
</code></pre></div><p>Ejemplo de un agente arquitecto (<code>architect.md</code>) ): </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;f7e8fbe1-8a9b-4638-9f2f-0004aaf199a6&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">---
description: "Arquitecto de software senior para proyectos Rails"
---

Eres un arquitecto de software senior especializado en aplicaciones Rails.

## Tu rol
- Evaluar decisiones de dise&#241;o antes de implementar
- Proponer patrones que escalen
- Identificar acoplamiento innecesario
- Revisar la separaci&#243;n de responsabilidades
- Proponer mejoras practicas conocidas en seguridad preferentemente frameworks NIST, OWASP, ISO27001, PCI.

## Reglas
- Siempre considera el impacto en performance
- Prefiere composici&#243;n sobre herencia
- Cada servicio debe tener una sola raz&#243;n para cambiar
- Documenta las decisiones con ADRs cuando sea relevante
- Manten actualizada la documentaci&#243;n
</code></pre></div><p><strong>Para usarlo:</strong> </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;12cf7d3d-fbb1-4cb2-a048-f67b1bbccbf3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">#&nbsp;En claude
@architect &#191;C&#243;mo deber&#237;a estructurar el m&#243;dulo de conciliaci&#243;n bancaria?</code></pre></div><h2>Nuevos features que me volaron la cabeza</h2><p><em><strong>Hooks</strong>:</em> Puedes definir hooks que se disparan antes o despu&#233;s de que Claude use una herramienta. Ejemplo: un <code>PostToolUse</code> que corre <code>prettier</code> autom&#225;ticamente despu&#233;s de cada edici&#243;n, o un <code>PreToolUse</code> que bloquea comandos peligrosos. Esto convierte a Claude Code en algo que se integra con tu pipeline, no que vive al lado.</p><p><em><strong>Computer Use</strong>:</em> Claude Code ahora puede interactuar con interfaces gr&#225;ficas &#8212; abrir tu browser, clickear, llenar formularios, correr tu app y verificar visualmente que funciona. Un ciclo completo de &#8220;escribo c&#243;digo &#8594; lo corro &#8594; verifico la UI &#8594; corrijo&#8221;, totalmente aut&#243;nomo.</p><p><em><strong>Dispatch</strong>:</em> Puedes asignar tareas desde el celular. Le mandas un prompt desde la app m&#243;vil, Claude Code trabaja en tu computador de escritorio, y te avisa cuando termin&#243;. Perfecto para lanzar una refactorizaci&#243;n mientras vai en el metro.</p><p><em><strong>Plugin Marketplace</strong>:</em> Plugins que extienden las capacidades de Claude Code. Ahora pueden incluir ejecutables en <code>bin/</code>, abriendo la puerta a integraciones m&#225;s potentes con herramientas externas.</p><p><strong>Cu&#225;ndo usar Claude Code</strong></p><ul><li><p><strong>Dise&#241;ar un feature nuevo</strong>: &#8220;Necesito agregar multi-tenancy a la app. &#191;Cu&#225;les son las opciones y tradeoffs?&#8221;</p></li><li><p><strong>Debugging complejo</strong>: &#8220;Este test falla intermitentemente en CI pero nunca en local. Analiza el c&#243;digo y las dependencias.&#8221;</p></li><li><p><strong>Refactoring arquitect&#243;nico</strong>: &#8220;Quiero extraer el m&#243;dulo de facturaci&#243;n a un engine de Rails. Prop&#243;n el plan.&#8221;</p></li><li><p><strong>Revisi&#243;n de seguridad</strong>: <code>@security-audit revisa el flujo de autenticaci&#243;n OAuth completo.</code></p></li><li><p><strong>Testing visual</strong>: Con Computer Use: &#8220;Corre la app, navega al formulario de login, prueba con credenciales inv&#225;lidas y reporta qu&#233; muestra la UI.&#8221;</p></li><li><p><strong>A/B Testing: </strong>&#8220;Dame 2 alternativas para decidir la mejor opci&#243;n a implementar en el hero del landing page.&#8221;</p></li></ul><p><strong>Pro tip: el scope del proyecto lo es todo</strong></p><p>Crea un archivo <code>CLAUDE.md</code> en la ra&#237;z de tu proyecto con el contexto que Claude Code necesita:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;f47398fe-59d9-4931-93c2-e7503436dc8a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown"># Contexto del proyecto (ultra resumido)

## Stack
- Rails 8.0.2, Ruby 4.0.2, PostgreSQL 17
- Hotwire (Turbo + Stimulus)
- Sidekiq para jobs async

## Convenciones
- Service objects en app/services/
- Form objects para validaciones complejas
- Queries complejas en app/queries/
- No usar callbacks de ActiveRecord para l&#243;gica de negocio

## Dominio
- SaaS contable para micro y peque&#241;a empresa chilena
- Integraci&#243;n con SII (Servicio de Impuestos Internos)
- Multi-tenant por cuenta de contador
- Open Core con licencia MIT para features base
</code></pre></div><p>Este archivo es tu multiplicador silencioso. Mientras mejor sea el contexto, mejores son las respuestas. Y ahora con contexto de hasta 1M de tokens (disponible para Max, Team y Enterprise con Opus 4.6), Claude Code puede tener en mente tu codebase completo.</p><p><em><strong>Disclaimer</strong></em><strong>: </strong>La version MAX tiene un valor de USD 100. En mi caso se paga totalmente. Pero depende de cada uno buscar el tier que mas le acomode. Si tienes dudas como aprovechar mejor tu plan de USD 20. Hablemos.</p><div><hr></div><h2>Paso 2: GitHub Copilot como tu ejecutor</h2><p><strong>Setup en VS Code</strong></p><ol><li><p>Instala la extensi&#243;n <strong>GitHub Copilot</strong> y <strong>GitHub Copilot Chat</strong></p></li><li><p>Aseg&#250;rate de tener un plan que incluya el Cloud Agent (Pro, Pro+, Business, Enterprise)</p></li><li><p>Habilita Agent Mode en la configuraci&#243;n</p></li></ol><p><strong>Las tres modalidades que uso</strong></p><p><strong>a) Inline completions (el cl&#225;sico)</strong></p><p>Copilot autocompleta mientras escribes. Funciona incre&#237;ble para boilerplate repetitivo, tests unitarios siguiendo patrones existentes, migraciones de base de datos, y c&#243;digo que sigue convenciones claras del proyecto.</p><blockquote><p><strong>Tip</strong>: mientras mejor nombrado est&#233; tu c&#243;digo, mejores son las sugerencias. Copilot se alimenta de contexto local.</p></blockquote><blockquote><p><strong>Tip</strong>: si ya tienes todo armado se vuelve un poco molesto. </p></blockquote><p><strong>b) Agent Mode en el editor</strong></p><p>Agent Mode est&#225; disponible tanto en VS Code como en JetBrains. Para tareas complejas dentro del editor:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;89532c35-7087-49a0-8024-d8d6a161be54&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">@workspace Agrega validaciones de RUT chileno al modelo Client,
incluyendo el algoritmo de verificaci&#243;n y tests unitarios
</code></pre></div><p><em>Agent Mode</em> determina qu&#233; archivos tocar, hace los cambios, corre comandos en terminal, e itera hasta completar la tarea. Ideal para implementar features bien definidos, agregar tests a c&#243;digo existente, y refactors multi-archivo acotados.</p><p>Dato importante: ahora puedes elegir qu&#233; modelo usa Copilot &#8212; GPT-5.4, Claude Opus 4.6, Gemini u o3 &#8212; dependiendo de la complejidad de la tarea. Mi favorito sigue siendo <strong>Sonnet 4.6</strong>.</p><p><strong>c) Cloud Agent (el game changer &#8212; actualizado abril 2026)</strong></p><p>Ac&#225; es donde Copilot brilla para ejecuci&#243;n aut&#243;noma. Lo que antes se llamaba &#8220;coding agent&#8221; ahora es <strong>Copilot Cloud Agent</strong>, y desde abril 2026 ya no est&#225; limitado a flujos de pull request.</p><p>Las novedades que cambiaron mi uso diario:</p><p><em><strong>Research y planificaci&#243;n sin PR</strong>:</em> Puedes pedirle a Copilot que investigue tu repo, arme un plan de implementaci&#243;n y espere tu aprobaci&#243;n antes de escribir una sola l&#237;nea. Antes ten&#237;a que crear un PR s&#237; o s&#237; &#8212; ahora no.</p><p><em><strong>Model picker</strong>:</em> Eliges qu&#233; modelo usa para cada tarea. Modelo r&#225;pido para tests simples, modelo pesado para un refactor complejo.</p><p><em><strong>Self-review con Code Review</strong>:</em> Copilot revisa su propio c&#243;digo antes de taguearte. Lo he visto m&#225;s de una vez corregirse solo &#8212; simplificando l&#243;gica innecesariamente compleja antes de que yo la vea.</p><p><em><strong>Security scanning integrado</strong>:</em> Code scanning, secret scanning y detecci&#243;n de dependencias vulnerables corren autom&#225;ticamente dentro del workflow del agente. Y gratis, aunque normalmente es parte de GitHub Advanced Security.</p><p><em><strong>50% m&#225;s r&#225;pido</strong>:</em> Desde marzo, el startup del agente es la mitad de r&#225;pido. El loop de feedback se siente mucho m&#225;s &#225;gil.</p><p>El flujo actualizado:</p><ol><li><p><strong>Asigna un issue a Copilot</strong> en GitHub o delega desde VS Code Chat</p></li><li><p>Copilot investiga el repo y genera un plan (nuevo: puedes revisarlo antes de que codee)</p></li><li><p>Codea en su propio ambiente, corre tests y linters</p></li><li><p>Hace self-review con Copilot Code Review + security scanning</p></li><li><p>Te deja un PR listo o un diff para revisar (nuevo: t&#250; eliges cu&#225;ndo crear el PR)</p></li></ol><p><strong>Lo que delego al Cloud Agent:</strong> issues de complejidad baja-media bien descritos, agregar tests a c&#243;digo sin cobertura, limpiar tech debt (dead code, deprecations), actualizar dependencias con cambios de API, documentaci&#243;n de c&#243;digo, y fix de vulnerabilidades detectadas por security scanning.</p><p><strong>Lo que NO delego:</strong> cambios arquitect&#243;nicos, l&#243;gica de negocio compleja, cualquier cosa que requiera entender el &#8220;por qu&#233;&#8221; del dominio.</p><p><strong>Configuraci&#243;n de agentes custom</strong></p><p>Crea archivos en <code>.github/agents/</code> para codificar las pr&#225;cticas de tu equipo:</p><pre><code><code># .github/agents/rails-contributor.md
name: Rails Contributor
description: Sigue nuestras convenciones de Rails para contribuciones

instructions: |
  - Usa service objects para l&#243;gica de negocio
  - Tests con RSpec, no Minitest
  - Factories con FactoryBot, no fixtures
  - Cada PR debe incluir tests
  - Migraciones reversibles siempre que sea posible
  - Sigue las convenciones de app/services/ para nuevos servicios
</code></code></pre><p><strong>Bonus</strong>: puedes usar agentes de terceros desde VS Code y GitHub &#8212; Claude de Anthropic y OpenAI Codex est&#225;n disponibles como agentes alternativos en Pro+ y Enterprise. </p><blockquote><p>S&#237;, puedes asignar un issue a Claude directamente desde GitHub. Y esto es genial cuando estas en el Gym, en el Uber o almorzando y viene la inspiraci&#243;n. Si tu despliegue es automatizado, puedes sincronizar en un ambiente bajo y probar los cambios entre serie y serie.</p></blockquote><div><hr></div><h2>Paso 3: Claude Cowork para todo lo dem&#225;s</h2><p><strong>Qu&#233; es</strong></p><p>Cowork es el motor ag&#233;ntico de Claude Code, pero accesible desde Claude Desktop sin terminal. Trabaja directo con tus archivos locales, carpetas y aplicaciones. Siento que pas&#243; de &#8220;preview interesante&#8221; o un <em>nice-to-have</em> a herramienta de productividad seria con Projects, Dispatch, Computer Use y Scheduled Tasks.</p><p><strong>Setup</strong></p><ol><li><p>Descarga <strong>Claude Desktop</strong> desde claude.com/download (macOS y Windows)</p></li><li><p>Necesitas un plan pagado (Pro, Max, Team o Enterprise)</p></li><li><p>Abre la app y cambia a la pesta&#241;a <strong>Cowork</strong></p></li><li><p>Apunta Claude a la carpeta con la que quieres trabajar</p></li></ol><p><strong>Lo que cambi&#243; todo: Dispatch + Computer Use + Scheduled Tasks</strong></p><p>Estas tres features juntas convirtieron a Cowork en algo que antes requer&#237;a scripts, APIs y horas de setup.</p><p><em><strong>Dispatch</strong>:</em> Una conversaci&#243;n continua entre tu celular y tu computador de escritorio. Le mandas una tarea desde la app m&#243;vil, Claude la ejecuta en tu desktop usando tus archivos locales, conectores y plugins, y te avisa cuando termin&#243;.</p><p>Ejemplo real: voy en el metro y le digo desde el celular &#8220;revisa las facturas que llegaron hoy a Gmail, descarga los PDFs y organ&#237;zalos en /facturas/2026-04/&#8221;. Cuando llego a la casa, est&#225; listo.</p><p><em><strong>Computer Use</strong>:</em> Claude literalmente usa tu computador &#8212; mueve el mouse, clickea botones, abre apps, navega el browser. No es metaf&#243;rico. Es literal. Funciona en macOS y Windows.</p><p>Esto desbloquea todo lo que antes no se pod&#237;a automatizar: interactuar con apps sin API, llenar formularios web, verificar UIs, trabajar con sistemas legacy.</p><p><em><strong>Scheduled Tasks</strong>:</em> Escribes un prompt una vez y Cowork lo ejecuta autom&#225;ticamente &#8212; cada hora, d&#237;a, semana, o cuando t&#250; quieras. Combinado con Dispatch y Computer Use, tienes automatizaci&#243;n real sin escribir una l&#237;nea de c&#243;digo.</p><blockquote><p>Un prompt de 10 lineas te permite leer, clasificar y responder tu bandeja de InMails de LinkedIn. Justo antes de desayunar.</p></blockquote><p><strong>Casos de uso reales que ocupo toda la semana</strong></p><p><em>Research y s&#237;ntesis</em></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;432336d1-7a27-470d-9da4-d3e01a80d735&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">Tengo estas 5 fuentes sobre regulaci&#243;n tributaria chilena para 2026
en la carpeta /research/tributario/. Necesito un resumen ejecutivo
con los cambios que impactan a micro y peque&#241;a empresa, organizado
por fecha de entrada en vigencia.
</code></pre></div><p>Cowork lee todos los archivos, sintetiza, y te entrega un documento estructurado.</p><p><em>Generaci&#243;n de documentos</em></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;fec808d6-62f6-4da7-a7d6-d386e140294e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">Con la data del sprint review de esta semana (en /sprints/2026-w14/),
genera un reporte para stakeholders con: velocidad del equipo,
items completados vs comprometidos, y blockers identificados.
Formato: Excel con gr&#225;ficos.
</code></pre></div><p>Cowork genera archivos Excel con f&#243;rmulas funcionales, PowerPoints con contenido real, documentos formateados. La we&#225; funciona.</p><p><em>Briefing matutino autom&#225;tico (Scheduled Task)</em></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;8863bdb1-15a3-4d4f-b75c-792a725c8a4a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">Todos los d&#237;as a las 8am:
- Revisa mis emails no le&#237;dos en Gmail del &#250;ltimo d&#237;a
- Revisa mi calendario para hoy
- Revisa los PRs abiertos en GitHub que necesitan mi review
- Genera un briefing con prioridades sugeridas
- D&#233;jalo en /briefings/YYYY-MM-DD.md
</code></pre></div><p>Esto corre solo. Cuando abro el computador, el briefing ya est&#225; ah&#237;.</p><p><em>Organizaci&#243;n de informaci&#243;n</em></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;89879f80-f9e7-4f85-bdf5-9390febec14f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">La carpeta /downloads/facturas-2026/ tiene 200+ PDFs de facturas
electr&#243;nicas. Renombra cada una con el formato
YYYY-MM-DD_RUT-emisor_monto.pdf y organ&#237;zalas en subcarpetas por mes.
</code></pre></div><p>Algo que a mano tomar&#237;a horas, Cowork lo resuelve en minutos.</p><p><em>An&#225;lisis de datos</em></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ef485151-1acc-4a8f-a994-1d60e1dc97c4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Revisa el archivo clientes.csv y dame un an&#225;lisis de:
- Distribuci&#243;n por comuna
- Ticket promedio por segmento
- Tasa de churn por mes de incorporaci&#243;n
Exporta los resultados como dashboard HTML interactivo.
</code></pre></div><p><strong>Conectores y Plugins</strong></p><p>Cowork se conecta a Google Drive, Gmail, DocuSign y FactSet. Adem&#225;s, el Plugin Marketplace (lanzado en marzo) tiene 15+ plugins verificados cubriendo dise&#241;o, operaciones, HR y m&#225;s. Puedes instalarlos desde claude.com/plugins.</p><p><strong>Pro tip: Projects en Cowork</strong></p><p>Organiza tu trabajo en Projects dentro de Cowork. Cada Project tiene su propio contexto, archivos, instrucciones, tareas programadas y memoria. Nada se mezcla entre proyectos distintos. Es como tener escritorios separados para cada cliente en vez de un solo escritorio lleno de papeles.</p><div><hr></div><h2>Paso 4: El workflow integrado</h2><p>Ac&#225; se junta todo. Este es mi flujo real para un feature nuevo:</p><p><strong>Fase 1: Investigaci&#243;n y dise&#241;o (Cowork + Claude Code)</strong></p><ol><li><p><strong>Cowork</strong>: &#8220;Investiga c&#243;mo otros SaaS contables de LATAM manejan la conciliaci&#243;n bancaria autom&#225;tica. Busca en /research/ y complementa con b&#250;squeda web.&#8221;</p></li><li><p><strong>Claude Code</strong>: &#8220;Dado nuestro modelo de datos actual y esta investigaci&#243;n, &#191;cu&#225;l es la mejor arquitectura para implementar conciliaci&#243;n bancaria? Considera que procesamos ~50k transacciones/mes por tenant.&#8221; &#8212; con 1M de tokens de contexto, puede tener todo el codebase en mente.</p></li></ol><p><strong>Fase 2: Planificaci&#243;n (Claude Code + Copilot)</strong></p><ol start="3"><li><p><strong>Claude Code</strong>: &#8220;Descomp&#243;n la implementaci&#243;n en issues de GitHub, cada uno independiente y deployable. Incluye criterios de aceptaci&#243;n y estimaci&#243;n de complejidad.&#8221;</p></li><li><p><strong>Copilot Cloud Agent</strong>: Le pido que investigue el repo y genere un plan de implementaci&#243;n para los issues m&#225;s complejos &#8212; sin crear PR todav&#237;a. Reviso el plan, ajusto, y reci&#233;n ah&#237; le doy luz verde.</p></li></ol><p><strong>Fase 3: Ejecuci&#243;n (Copilot Cloud Agent + Editor)</strong></p><ol start="5"><li><p><strong>Copilot Cloud Agent</strong>: Asigno los issues de complejidad baja-media directamente a Copilot. Modelo r&#225;pido para los triviales, modelo pesado para los que tienen edge cases.</p></li><li><p><strong>Copilot Editor (Agent Mode)</strong>: Los issues m&#225;s complejos los trabajo en pair con Agent Mode, donde yo gu&#237;o y Copilot ejecuta.</p></li></ol><p><strong>Fase 4: Review y documentaci&#243;n (Claude Code + Cowork)</strong></p><ol start="7"><li><p><strong>Claude Code</strong>: Reviso las PRs generadas por Copilot a nivel arquitect&#243;nico: &#8220;&#191;Este approach escala? &#191;Hay edge cases que no estamos cubriendo?&#8221; &#8212; con <code>@security-audit</code> para un chequeo de seguridad.</p></li><li><p><strong>Cowork</strong>: &#8220;Con los PRs mergeados esta semana, actualiza la documentaci&#243;n t&#233;cnica en /docs/ y genera el changelog para el release.&#8221; &#8212; esto lo tengo como Scheduled Task que corre los viernes.</p></li></ol><div><hr></div><h2>Paso 5: Reglas que mantengo</h2><p>Despu&#233;s de muchos de errores, estas son las reglas que sigo:</p><p><strong>1. Nunca delegues lo que no entiendes.</strong> Si no puedes revisar cr&#237;ticamente el output de la IA, no deber&#237;as estar deleg&#225;ndole esa tarea. Las herramientas amplifican tu capacidad, no la reemplazan. Esto aplica triple con Computer Use &#8212; Claude puede hacer cosas irreversibles en tu computador.</p><p><strong>2. El contexto es el multiplicador.</strong> Invierte tiempo en escribir buenos <code>CLAUDE.md</code>, <code>AGENTS.md</code>, y descripciones de issues. El ROI es brutal: 30 minutos de contexto te ahorran horas de iteraci&#243;n con resultados mediocres.</p><p><strong>3. Cada herramienta en su capa.</strong> Cuando me pillo usando Claude Code para algo que Copilot hace mejor (autocompletar, ejecutar un issue simple), me detengo y cambio. Y viceversa. No mezcles.</p><p><strong>4. Revisa todo.</strong> Los PRs de Copilot Agent pasan por el mismo review que cualquier PR humano. Claude Code puede equivocarse en edge cases. Cowork puede sintetizar informaci&#243;n incorrecta. Tu criterio es el &#250;ltimo filtro. El self-review de Copilot y el security scanning ayudan, pero no reemplazan tus ojos.</p><p><strong>5. Itera el setup, no solo el c&#243;digo.</strong> Cada semana reviso qu&#233; funcion&#243; y qu&#233; no en el workflow. Los archivos de agente se actualizan, las instrucciones de proyecto se refinan, los prompts mejoran. Usa <code>/powerup</code> en Claude Code &#8212; son lecciones interactivas que te ense&#241;an features que probablemente no est&#225;s usando.</p><p><strong>6. Controla los permisos.</strong> Con Dispatch y Computer Use, Claude tiene acceso real a tu m&#225;quina. Revisa qu&#233; carpetas y conectores tiene habilitados. Piensa en el peor caso, no en el caso esperado.</p><div><hr></div><h2>Setup m&#237;nimo para empezar hoy</h2><p>Si todo esto te parece mucho, ac&#225; va el MVP del workflow:</p><ol><li><p><strong>Instala Claude Code</strong> &#8594; <code> brew install --cask claude-code</code> (5 min)</p></li><li><p><strong>Crea un CLAUDE.md</strong> con el contexto de tu proyecto (30 min)</p></li><li><p><strong>Crea al menos un subagente</strong> en <code>.claude/commands/</code> (10 min)</p></li><li><p><strong>Habilita Copilot Agent Mode</strong> en VS Code (5 min)</p></li><li><p><strong>Asigna tu primer issue a Copilot</strong> en GitHub (2 min)</p></li><li><p><strong>Descarga Claude Desktop</strong>, abre Cowork y pru&#233;balo con una tarea real (10 min)</p></li><li><p><strong>Configura Dispatch</strong> conectando la app m&#243;vil con el desktop (5 min)</p></li></ol><p>En poco m&#225;s de una hora tienes el stack funcionando. Despu&#233;s vas iterando y agregando complejidad seg&#250;n lo necesites.</p><div><hr></div><h2>Reflexi&#243;n final</h2><p>No estamos en la era de &#8220;la IA me reemplaza&#8221; ni en la de &#8220;la IA no sirve&#8221;. Estamos en la era de <strong>armar tu propio equipo de agentes</strong>, donde cada uno tiene su especialidad y t&#250; diriges la orquesta.</p><p>Claude Code piensa. Copilot ejecuta. Cowork orquesta el resto.</p><p>Y con Dispatch, Computer Use y Scheduled Tasks, ese equipo ahora trabaja aunque no est&#233;s sentado frente al computador.</p><p>La pregunta no es si usar IA para desarrollar. La pregunta es si est&#225;s usando las herramientas correctas en las capas correctas.</p><p>Y si todav&#237;a est&#225;s copiando y pegando prompts en un chatbot para todo... hay un 10x esper&#225;ndote en la mesa.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro Gomez&#8217;s personal blog! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Piloto Automático - Hablemos de Sostenibilidad.]]></title><description><![CDATA[Tercer cap&#237;tulo de nuestro podcast experimental.]]></description><link>https://sandrogomez.com/p/piloto-automatico-hablemos-de-sostenibilidad</link><guid isPermaLink="false">https://sandrogomez.com/p/piloto-automatico-hablemos-de-sostenibilidad</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Wed, 25 Mar 2026 04:44:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/Ihb_c16W87E" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#191;Qu&#233; nos depara el futuro tras la COP30? </p><p>&#127757; En este episodio de Piloto Autom&#225;tico, analizamos junto a Daniela Ram&#237;rez las nuevas tendencias en sostenibilidad y c&#243;mo transformar&#225;n el mercado y la tecnolog&#237;a. Una charla esencial para entender los desaf&#237;os que vienen. &#161;Dale play!  &#9654;&#65039;</p><div id="youtube2-Ihb_c16W87E" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;Ihb_c16W87E&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/Ihb_c16W87E?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro Gomez&#8217;s personal blog! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Piloto Automático - Reconversión laboral, oportunidades y desafíos.]]></title><description><![CDATA[Segundo cap&#237;tulo de nuestro podcast experimental.]]></description><link>https://sandrogomez.com/p/piloto-automatico-reconversion-laboral</link><guid isPermaLink="false">https://sandrogomez.com/p/piloto-automatico-reconversion-laboral</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Wed, 25 Mar 2026 04:41:37 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/1eF26ySa5CY" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#127897;&#65039; Hablamos con Diego Arias sobre el futuro del trabajo: c&#243;mo la IA est&#225; transformando nuestras profesiones, los desaf&#237;os y oportunidades que trae esta nueva era, el impacto del cambio generacional y las nuevas formas de aprender en un mundo que evoluciona r&#225;pido.<br><br>&#128073; Conoce m&#225;s sobre Diego Arias: https://www.linkedin.com/in/godiegoarias/</p><div id="youtube2-1eF26ySa5CY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;1eF26ySa5CY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/1eF26ySa5CY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro Gomez&#8217;s personal blog! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Piloto Automático - El futuro del trabajo.]]></title><description><![CDATA[Primer cap&#237;tulo de nuestro podcast experimental.]]></description><link>https://sandrogomez.com/p/piloto-automatico-el-futuro-del-trabajo</link><guid isPermaLink="false">https://sandrogomez.com/p/piloto-automatico-el-futuro-del-trabajo</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Wed, 25 Mar 2026 04:38:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/EhoU5_bs8jA" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Una conversaci&#243;n con Claudia Arce acerca del futuro del trabajo. Una conversaci&#243;n importante si tienes un perfil profesional y/o ejecutivo, lideras equipos, est&#225;s buscando tu pr&#243;ximo desaf&#237;o o simplemente est&#225;s potenciando tu liderazgo.</p><div id="youtube2-EhoU5_bs8jA" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;EhoU5_bs8jA&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/EhoU5_bs8jA?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro Gomez&#8217;s personal blog! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Development Engine for Complex Data Platforms (part II) ]]></title><description><![CDATA[Setting up the enablers: CLAUDE.md, skills, and the unified extensibility system that embeds architectural discipline into the development process.]]></description><link>https://sandrogomez.com/p/development-engine-for-complex-data</link><guid isPermaLink="false">https://sandrogomez.com/p/development-engine-for-complex-data</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Sat, 21 Mar 2026 03:31:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/dbd89906-3894-440c-9260-e85a4f1c9b7f_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>01 &#183; The Development Problem Behind Data Platforms</h2><p>Building a medallion-architecture platform pipelines across multiple processing domains creates a specific engineering challenge that has nothing to do with the data itself: <strong>how do you keep architectural discipline consistent across every notebook, every pipeline, and every environment as the platform evolves?</strong></p><p>Quality rules get forgotten. Partition keys get omitted. Configuration patterns drift between notebooks. A new developer copies an old notebook and misses the latest pattern. A production fix bypasses the MERGE pattern and introduces duplicates. These are not hypothetical risks &#8212; they are the natural entropy of any complex codebase under active development.</p><p>Traditional approaches &#8212; code reviews, style guides, wiki documentation &#8212; rely on human attention. They work until the platform reaches a scale where no single person can hold the full architectural context. Claude Code solves this by embedding the platform&#8217;s architectural knowledge directly into the development toolchain.</p><div><hr></div><h2>02 &#183; The Technology Stack</h2><p>Before discussing how Claude Code helps, it is worth mapping the stack that needs to be maintained. Each component has specific configuration requirements, failure modes, and interaction patterns that must be consistently applied across every pipeline.</p><ul><li><p><strong>Microsoft Fabric</strong> &#8212; Unified analytics platform. Lakehouses, pipelines, notebooks, and scheduling under one capacity.</p></li><li><p><strong>Delta Lake</strong> &#8212; ACID transactions on the lakehouse. MERGE/UPSERT for idempotent writes. Schema enforcement at Silver layer.</p></li><li><p><strong>Apache Spark</strong> &#8212; All transformation logic in PySpark notebooks. Shared sessions via orchestrator pattern. Window functions for time-series continuity.</p></li><li><p><strong>Azure Cosmos DB</strong> &#8212; Low-latency serving layer for real-time dashboards. Partition discipline enforced by code. REST API exposure.</p></li><li><p><strong>Azure Key Vault</strong> &#8212; Secrets management. 3-tier config cascade: Key Vault &#8594; Spark Config &#8594; Default Value across all environments.</p></li><li><p><strong>Terraform</strong> &#8212; Infrastructure as Code for capacity provisioning, Cosmos DB accounts, Key Vault policies, and network rules.</p></li></ul><p>The challenge is not any single component &#8212; it is the <strong>interactions between them</strong>. A Cosmos container defined in Terraform must match the partition key used in the notebook that writes to it. A Key Vault secret path must be consistent across the Terraform policy, the Spark config, and the notebook&#8217;s fallback default. These cross-cutting dependencies are exactly where drift causes silent failures.</p><div><hr></div><h2>03 &#183; Why Claude Code for Data Platform Development</h2><p>A data platform is not a web app. There is no <code>npm run dev</code>. The development loop involves PySpark notebooks that run on remote clusters, Delta Lake tables you can only inspect by querying, documents in a serving layer that silently misdirect if a partition key is missing, and Terraform plans that manage infrastructure across three environments.</p><p>Claude Code fits this workflow because it operates in the terminal &#8212; the same place where you run <code>az login</code>, <code>terraform plan</code>, pipe logs, and inspect tables. It reads the full project structure, understands architectural context from CLAUDE.md, and executes agentic workflows that chain multiple tools: search the codebase for all MERGE statements, validate partition key consistency across Terraform and notebooks, run a lint pass, and generate a compliance report &#8212; all in a single session.</p><blockquote><p><strong>The Strategic Value</strong></p><p>The value of Claude Code for data platforms is not speed &#8212; it is <strong>consistency at scale</strong>. When every notebook must follow the same structure, every write must use the same pattern, and every deployment must pass the same governance checks, the question is not whether rules will be violated. It is how quickly those violations get caught. Claude Code shifts detection from code review (hours/days) to code generation (instant).</p></blockquote><div><hr></div><h2>04 &#183; CLAUDE.md &#8212; The Platform&#8217;s Persistent Memory</h2><p>The CLAUDE.md file sits at the root of the repository. It encodes the architectural decisions, quality rules, naming conventions, and environment setup that every developer &#8212; human or AI &#8212; must follow. Claude Code reads it at the start of every session. No repetition, no drift.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;e1266101-ffe3-48d5-a30e-06b542d59604&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown"># Data Platform &#8212; Real-Time Analytics Platform

## Project Overview
Medallion architecture on Microsoft Fabric (F4 capacity).
Bronze &#8594; Silver &#8594; Gold &#8594; Cosmos DB / Power BI serving layer.
Three processing domains: orchestrated batch, hybrid event/scheduled,
incremental replication. 15+ active pipelines.

## Architecture Rules
- Every write uses Delta Lake MERGE (UPSERT). No append-only writes.
- Every Cosmos DB document MUST include partition_date field.
- All fact-to-dimension joins MUST be LEFT JOIN with count guard.
- Every cache() must have a matching unpersist().
- Named constants only. No hardcoded literals for thresholds.
- Imports at module top level. Never inside loops or conditionals.

## Environment Configuration
3-tier cascade: Key Vault &#8594; Spark Config &#8594; Default Value.
Notebooks MUST work standalone (dev) and under orchestrator (prod).
@docs/environment-setup.md for Key Vault paths per environment.

## Notebook Structure
Every notebook follows: Config &#8594; Read &#8594; Transform &#8594; Write &#8594; Cleanup.
Orchestrator children detect shared temp views via try/except.
Fallback file discovery scans last N timestamped folders via regex.

## Validation
- spark-submit --deploy-mode local for unit testing
- Domain-specific thresholds: @docs/validation-rules.md
- Geospatial: reject coordinates outside configured bounding box
- Alert classification: auto-computed, not manually overridable

## Documentation
Every code change requires a docs update in the same commit.
User-facing docs are bilingual (Spanish/English).
See @docs/checklist-template.md for mandatory checklist.
</code></pre></div><p>This file is under 60 lines. It does not try to cover everything &#8212; it uses <code>@path</code> imports to reference deeper documentation that Claude reads only when working on related tasks. This follows the progressive disclosure principle: load context only when it is relevant.</p><blockquote><p><strong>Design Principle</strong></p><p>A good CLAUDE.md is not a knowledge dump &#8212; it is a <strong>routing table</strong>. It tells Claude what the rules are and where to find deeper context. The architecture rules section encodes the six quality rules from the platform. The <code>@docs/</code> references point to validation thresholds, environment configs, and schema definitions that change more frequently than the architectural patterns themselves.</p></blockquote><div><hr></div><h2>05 &#183; The Unified Skills System</h2><p>The unified skills (<code>.claude/skills/</code>)  system has two invocation modes:</p><ul><li><p><strong>User-invoked skills</strong> are triggered explicitly with <code>/skill-name</code>. These are the workflows you call when you need them &#8212; creating a notebook, running a governance audit, validating infrastructure consistency.</p></li><li><p><strong>Agent-invoked skills</strong> are loaded automatically by Claude when it recognizes a matching context. If a skill&#8217;s <code>description</code> field matches what you are working on, Claude loads it without being asked. This means a skill describing &#8220;Spark notebook creation&#8221; can activate automatically when Claude detects you are building a new pipeline.</p></li></ul><p>Every skill lives in its own directory with a <code>SKILL.md</code> as the entry point. The SKILL.md file has two parts: YAML frontmatter that controls when and how the skill runs, and markdown content with the instructions Claude follows.</p><blockquote><p><strong>What Skills Can Do Now</strong></p><p>Beyond simple prompt instructions, the current skills system supports: <strong>frontmatter fields</strong> that restrict which tools Claude can use (<code>allowed-tools</code>), override the model (<code>model</code>), or spawn the skill as an isolated subagent (<code>agent: true</code>); <strong>supporting files</strong> like templates, example outputs, and validation scripts that live alongside SKILL.md; and <strong>dynamic context injection</strong> via <code>!command</code> syntax that runs a shell command and injects its output into the skill prompt before Claude sees it. This makes skills genuinely programmable, not just instructional.</p></blockquote><div><hr></div><h2>06 &#183; Pipeline Creation Skills</h2><p>The most valuable skills for a data platform encode the pipeline structure itself, so every new notebook starts compliant. Here is the spark-notebook skill with proper frontmatter:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;e2efab43-f7cb-44e2-8a81-3a609845e8e0&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">.claude/skills/spark-notebook/
&#9500;&#9472;&#9472; SKILL.md                    # Main instructions (required)
&#9500;&#9472;&#9472; templates/
&#9474;   &#9492;&#9472;&#9472; notebook-template.py    # Skeleton Claude fills in
&#9500;&#9472;&#9472; examples/
&#9474;   &#9492;&#9472;&#9472; silver-telemetry.py     # Reference output showing expected format
&#9492;&#9472;&#9472; scripts/
    &#9492;&#9472;&#9472; validate-structure.sh   # Script to verify cell order compliance
</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;e5fa0b43-ebf4-407e-ab43-ba196a271003&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">---
name: spark-notebook
description: &gt;
  Creates or modifies PySpark notebooks for the Data platform.
  Use when building new pipelines, adding analytical notebooks, or
  refactoring existing notebooks to match the mandatory structure.
allowed-tools:
  - Read
  - Write
  - Bash(spark-submit:*)
  - Bash(python:*)
---

# Spark Notebook Creation Skill

When creating or modifying a PySpark notebook for this platform,
follow this structure strictly.

## Mandatory Cell Order
1. Parameters cell &#8212; Fabric parameters + inj_* injected params
2. Configuration cell &#8212; 3-tier config resolution
3. Source reading cell &#8212; Check for shared temp views first
4. Transformation cells &#8212; Business logic with named constants
5. Write cell &#8212; Delta Lake MERGE with composite key
6. Serving sync cell &#8212; Include partition_date in every document
7. Cleanup cell &#8212; unpersist() all cached DataFrames

## Config Resolution Pattern
Always implement the 3-tier cascade:

    endpoint = spark.conf.get(
        "spark.dataplatform.cosmos.endpoint",
        "https://default-dev.documents.azure.com"
    )

## Orchestrator Detection

    try:
        df = spark.sql("SELECT * FROM tmp_source_data")
        running_under_orchestrator = True
    except:
        df = spark.read.parquet(fallback_path)
        running_under_orchestrator = False

## Write Pattern
ALWAYS use MERGE. Never .mode("overwrite") or .mode("append"):

    delta_table.alias("target").merge(
        df.alias("source"),
        "target.entity_id = source.entity_id AND
         target.event_date = source.event_date"
    ).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute()

## Anti-Patterns (reject if found)
- NEVER use .mode("overwrite") on Silver/Gold tables
- NEVER omit partition_date in serving-layer documents
- NEVER use cache() without unpersist()
- NEVER hardcode thresholds as inline literals

## Supporting Files
- See templates/notebook-template.py for the cell skeleton
- See examples/silver-telemetry.py for a complete reference
- Run scripts/validate-structure.sh to verify compliance
</code></pre></div><p>When a developer types <code>/spark-notebook</code>, Claude loads the skill, reads the supporting files for context, follows the cell structure, and produces a notebook that is already compliant with every quality rule. Because the <code>description</code> field mentions &#8220;building new pipelines&#8221; and &#8220;refactoring existing notebooks,&#8221; Claude can also load this skill automatically when it detects related work &#8212; no slash command needed.</p><p>The same approach works for other repeatable patterns: a <strong>telemetry-ingestion</strong> skill that encodes the hybrid event/scheduled execution modes, a <strong>tail-fetching</strong> skill that encodes the incremental replication pattern with LEAD window functions, or a <strong>serving-sync</strong> skill that enforces partition discipline and retry logic. Each gets its own directory, its own frontmatter, and its own supporting files.</p><div><hr></div><h2>07 &#183; Governance Audit Skills</h2><p>Where pipeline creation skills help <em>create</em> correct code, governance audit skills help <em>verify</em> that existing code stays correct. These are user-invoked skills &#8212; you call them explicitly when you need a cross-cutting check.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;cd77e96d-c47e-4dc3-b2b0-62f75f0b9181&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">---
name: validate-serving-layer
description: &gt;
  Scans all notebooks that write to the serving layer and verifies
  partition key presence, naming conventions, and retry logic.
  Use before commits, during PR reviews, or as a pre-deploy check.
allowed-tools:
  - Read
  - Bash(grep:*)
  - Bash(find:*)
---

# Validate Serving Layer Documents

Scan all notebooks in the repository that write to Cosmos DB.
For each one, verify:

1. Every document dictionary includes a "partition_date" key
2. The partition key value is derived from data, not hardcoded
3. The container name matches convention: "gold-{domain}-{entity}"
4. Error handling wraps the write with retry logic

Report findings as a table:
| Notebook | Container | partition_date present | Naming OK | Retry logic |

Flag any notebook that fails any check as NEEDS FIX with severity.
</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;d3ac9022-32ea-4123-9249-fa82ab029447&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">---
name: audit-cache
description: &gt;
  Finds orphaned cache() calls without matching unpersist().
  Critical on constrained Spark capacity where orphaned caches
  cause OOM crashes on shared sessions.
allowed-tools:
  - Read
  - Bash(grep:*)
---

# Audit Cache/Unpersist Pairs

Search all .py and notebook files for .cache() calls.
For each cached DataFrame, verify a matching .unpersist()
exists in the same notebook.

On constrained capacity, orphaned caches cause OOM crashes
on shared Spark sessions. This is a production blocker.

List all violations with the exact line where
unpersist() should be added.
</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;2e8b71cc-723d-4412-9f6b-208ecea60e02&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml">---
name: check-merge-keys
description: &gt;
  Verifies that every Delta Lake MERGE operation uses the correct
  composite key as documented in the table schemas. Partial keys
  cause silent duplicates that compound over time.
allowed-tools:
  - Read
  - Bash(grep:*)
context:
  - docs/table-schemas.md
---

# Check MERGE Key Consistency

For every Delta Lake MERGE operation in the codebase:
1. Extract the merge condition (composite key)
2. Verify the key matches the table's documented primary key
   in @docs/table-schemas.md
3. Flag any MERGE that uses a partial key &#8212; this causes
   silent duplicates that compound over time

Report as: | Table | Expected Key | Actual Key | Match? |
</code></pre></div><p>Notice the frontmatter differences. The <code>validate-serving-layer</code> skill restricts tools to <code>Read</code> and basic <code>Bash</code> commands &#8212; it is an auditor, not a modifier. The <code>check-merge-keys</code> skill uses the <code>context</code> field to automatically load the table schemas documentation, so Claude has the reference data it needs without searching for it.</p><p>Running <code>/validate-serving-layer</code> takes seconds and catches the exact failure mode that cost days to debug in production: a serving database silently misdirecting documents when a partition key is missing. The skill encodes that institutional knowledge permanently &#8212; it does not depend on any individual remembering to check.</p><blockquote><p><strong>Agent Skills vs. User-Invoked Skills</strong></p><p>Governance audits are user-invoked &#8212; you call <code>/validate-serving-layer</code> when you want a check. But the spark-notebook skill can work both ways: invoked explicitly with <code>/spark-notebook</code>, or loaded automatically when Claude detects you are creating a new pipeline. The <code>description</code> field in the frontmatter is what drives automatic loading. Write it like a search query for the kind of work it applies to, and Claude will load it when the context matches.</p></blockquote><div><hr></div><h2>08 &#183; Built-in Skills Worth Knowing</h2><p>Claude Code ships with bundled skills that complement custom platform skills. Several are directly relevant to data platform development:</p><ul><li><p><code>/review</code> &#8212; Code review with context-aware analysis. Useful for catching quality rule violations in PRs before custom audit skills run.</p></li><li><p><code>/simplify</code> &#8212; Refactors complex code for clarity. On a platform where notebook readability directly affects maintainability, this is high leverage.</p></li><li><p><code>/batch</code> &#8212; Runs a command across multiple files. Combined with audit skills, this enables bulk compliance checks: &#8220;run <code>/audit-cache</code> across all notebooks in the telemetry domain.&#8221;</p></li><li><p><code>/loop</code> &#8212; Executes a prompt at recurring intervals within a session. Acts as a lightweight monitoring layer during deployment windows: <code>/loop 30m "check pipeline logs for CRITICAL errors"</code>.</p></li><li><p><code>/debug</code> &#8212; Reads the session debug log and diagnoses Claude Code issues. Useful when a skill behaves unexpectedly or a tool call fails silently.</p></li></ul><p>These bundled skills work alongside custom skills. A typical governance workflow might chain <code>/review</code> for general code quality, then <code>/validate-serving-layer</code> for platform-specific checks, then <code>/audit-cache</code> for memory safety &#8212; all in the same session.</p><div><hr></div><h2>What&#8217;s Next</h2><p>This post covered the <strong>setup</strong>: CLAUDE.md as the architectural routing table, the unified skills system with frontmatter and supporting files, pipeline creation skills that encode mandatory structures, and governance audit skills that verify compliance.</p><p>In <strong>Part III</strong>, we take these enablers into production. We cover how the six quality rules become an enforceable governance framework, how Terraform and notebook code are cross-referenced to prevent infrastructure drift, a complete Spark notebook example using the tail-fetching pattern, how auto memory compounds debugging insights across sessions, and how agentic workflows chain everything into full-repository audits that run in seconds.</p><div><hr></div><p><em>Claude Code &#183; CLAUDE.md &#183; Unified Skills &#183; Frontmatter &#183; PySpark &#183; Delta Lake &#183; Data Governance &#183; Platform Engineering</em></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro Gomez&#8217;s personal blog! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="pullquote"><p><strong>Disclaimer:</strong> Built from the ground up using documentation and diagrams from production-scale Medallion architectures. While Claude assisted in the structural organization of this post, all technical strategies and data-processing milestones are derived from my direct professional practice.</p></div>]]></content:encoded></item><item><title><![CDATA[Enforcing Data Quality and Governance with Claude Code (part III)]]></title><description><![CDATA[From rules to enforcement: how the skills from Part II become a governance framework, an infrastructure cross-check, and a compounding knowledge system.]]></description><link>https://sandrogomez.com/p/enforcing-data-quality-and-governance</link><guid isPermaLink="false">https://sandrogomez.com/p/enforcing-data-quality-and-governance</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Sat, 21 Mar 2026 03:30:54 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/586b8ea0-5ca3-45d6-beae-db55979ab9d9_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Quick Recap</h2><p>In Part II, we set up the enablers that embed architectural knowledge into Claude Code for a data platform:</p><ul><li><p><strong>CLAUDE.md</strong> &#8212; the platform&#8217;s persistent memory: architecture rules, quality gates, and environment configuration loaded at every session start.</p></li><li><p><strong>Pipeline creation skills</strong> &#8212; skills with frontmatter and supporting files (templates, examples, validation scripts) that encode the mandatory notebook structure, so every new pipeline starts compliant. Auto-loaded by Claude when it detects relevant work, or invoked explicitly with <code>/spark-notebook</code>.</p></li><li><p><strong>Governance audit skills</strong> &#8212; user-invoked skills (<code>/validate-serving-layer</code>, <code>/audit-cache</code>, <code>/check-merge-keys</code>) that verify existing code against the quality rules in seconds. Each uses <code>allowed-tools</code> to restrict itself to read-only operations.</p></li><li><p><strong>Bundled skills</strong> &#8212; <code>/review</code>, <code>/batch</code>, <code>/loop</code>, and <code>/debug</code> ship with Claude Code and chain with custom skills for comprehensive governance workflows.</p></li></ul><p>This post takes those enablers into production. We show how a representative set of six quality rules&#8212;illustrative rather than exhaustive&#8212;can be operationalized into an enforceable framework, how a dedicated skill cross-references Terraform and notebook code, what a complete Spark notebook looks like when generated by the skill, and how auto memory and agentic workflows compound the platform&#8217;s resilience over time.</p><div><hr></div><h2>01 &#183; Data Quality and Governance Through Claude Code</h2><p>The six quality rules from the platform architecture are not documentation &#8212; they become enforceable checks when embedded into the skills system. Each rule maps to a specific skill, a specific mechanism, and a specific moment in the development cycle:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_-0o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_-0o!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 424w, https://substackcdn.com/image/fetch/$s_!_-0o!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 848w, https://substackcdn.com/image/fetch/$s_!_-0o!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 1272w, https://substackcdn.com/image/fetch/$s_!_-0o!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_-0o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png" width="1440" height="1144" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1144,&quot;width&quot;:1440,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:207414,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191644819?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_-0o!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 424w, https://substackcdn.com/image/fetch/$s_!_-0o!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 848w, https://substackcdn.com/image/fetch/$s_!_-0o!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 1272w, https://substackcdn.com/image/fetch/$s_!_-0o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fababcafd-b033-4110-a2f4-2678971c3fdd_1440x1144.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Powered by Claude (epic feature).</figcaption></figure></div><p>Notice the mix of enforcement types. Pipeline creation skills (like <code>spark-notebook</code>) prevent violations at generation time &#8212; the code is never wrong in the first place. Governance audit skills (like <code>/validate-serving-layer</code> and <code>/audit-cache</code>) verify existing code retroactively. And CLAUDE.md rules apply to every session regardless of which skill is active. The three layers overlap by design: if a creation skill misses something, an audit skill catches it; if both miss it, auto memory (Section 04) learns from the production failure and flags it next time.</p><blockquote><p><strong>The Governance Feedback Loop</strong></p><p>When Claude Code detects a violation &#8212; an orphaned <code>cache()</code> or a missing partition key &#8212; it does not just flag the problem. It explains <strong>why</strong> the rule exists (OOM on shared sessions, silent data loss in the serving layer) and suggests the exact fix. Over time, this trains the development team to internalize the rules, not just follow them. The tool becomes a teaching mechanism, not just a linting tool.</p></blockquote><p>For domain-specific data quality, Claude Code validates incoming data patterns against documented thresholds. Coordinates outside valid bounding boxes, sensor readings outside physical ranges, alert classifications that must be computed consistently &#8212; all of these can be checked through a single audit skill that reads both the code and the validation rules documentation referenced via the <code>context</code> frontmatter field.</p><div><hr></div><h2>02 &#183; Terraform &#8212; Infrastructure-to-Application Consistency</h2><p>Infrastructure as Code is not just about provisioning. In a data platform, the Terraform definitions create the contract that application code must follow: container names, partition key paths, throughput settings, Key Vault policies. Claude Code helps enforce that contract through a dedicated cross-check skill.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;3755ae50-7748-4554-96f7-28aee7ad9c2b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown"># infra/modules/cosmos/main.tf

resource "azurerm_cosmosdb_account" "analytics" {
  name                = "dataplatform-${var.environment}-cosmos"
  location            = var.location
  resource_group_name = var.resource_group_name
  offer_type          = "Standard"
  kind                = "GlobalDocumentDB"

  consistency_policy {
    consistency_level = "Session"
  }
}

resource "azurerm_cosmosdb_sql_database" "analytics_db" {
  name                = "operational-analytics"
  resource_group_name = var.resource_group_name
  account_name        = azurerm_cosmosdb_account.analytics.name
}

# One container per Gold-layer entity
resource "azurerm_cosmosdb_sql_container" "batch_kpis" {
  name                = "gold-batch-kpis"
  resource_group_name = var.resource_group_name
  account_name        = azurerm_cosmosdb_account.analytics.name
  database_name       = azurerm_cosmosdb_sql_database.analytics_db.name
  partition_key_paths  = ["/partition_date"]   # &#8592; Must match notebook code
  throughput          = 400
}
</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;aec8dfd7-e283-4bf7-ac88-5127dcfb2983&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown"># infra/modules/fabric/main.tf

resource "azurerm_fabric_capacity" "analytics" {
  name                = "dataplatform-${var.environment}"
  resource_group_name = var.resource_group_name
  location            = var.location
  sku {
    name = "F4"     # 4 CU ceiling &#8212; budget constraint
    tier = "Fabric"
  }
}

resource "azurerm_key_vault" "dataplatform" {
  name                     = "kv-dataplatform-${var.environment}"
  location                 = var.location
  resource_group_name      = var.resource_group_name
  sku_name                 = "standard"
  tenant_id                = data.azurerm_client_config.current.tenant_id
  purge_protection_enabled = true
}
</code></pre></div><p>This cross-boundary check is a natural fit for the skills system. A dedicated skill can auto-load the Terraform files via the <code>context</code> frontmatter field and cross-reference them against notebook write targets:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;c8e9c4fa-4da4-4001-84a5-5af3099d96b4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">---
name: check-infra-consistency
description: &gt;
  Cross-references Terraform Cosmos DB container definitions against
  notebook write targets. Detects partition key mismatches, missing
  containers, and naming convention violations across infrastructure
  and application code.
allowed-tools:
  - Read
  - Bash(grep:*)
  - Bash(find:*)
context:
  - infra/modules/cosmos/main.tf
  - docs/table-schemas.md
---

# Check Infrastructure-to-Application Consistency

1. Parse all Cosmos container definitions in infra/modules/cosmos/
   Extract: container name, partition_key_paths, database name
2. Search all notebooks for Cosmos write operations
   Extract: target container name, partition key field in document
3. Cross-reference:
   - Does every notebook container match a Terraform definition?
   - Does every Terraform container have a notebook that writes to it?
   - Do partition key paths match between infra and application code?
4. Check naming convention: "gold-{domain}-{entity}" in both layers

Report as:
| Container | In Terraform | In Notebooks | Partition Key Match | Naming OK |

Flag mismatches as CRITICAL &#8212; these cause silent data loss.
</code></pre></div><p>This is the kind of drift that traditional CI/CD pipelines do not cover because it spans two different codebases &#8212; infrastructure and application. A single skill bridges both.</p><div><hr></div><h2>03 &#183; Spark Notebook &#8212; The Tail-Fetching Pattern in Practice</h2><p>Here is a simplified version of the incremental replication pattern &#8212; the technique that bridges batch boundaries for gapless time series. This is what Claude Code generates when the <code>/spark-notebook</code> skill is invoked. The skill loads its supporting files &#8212; the cell skeleton from <code>templates/notebook-template.py</code> and the reference implementation from <code>examples/silver-telemetry.py</code> &#8212; then produces a notebook where every cell follows the mandatory structure, every config uses the 3-tier cascade, and every quality rule is applied automatically.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;86f26339-ed80-4701-9c6e-33b9a05bab8a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># notebooks/silver_incremental_telemetry.py

# &#9472;&#9472; Cell 1: Parameters &#9472;&#9472;
inj_config = ""   # Injected by orchestrator, empty if standalone
environment = "dev"

# &#9472;&#9472; Cell 2: Configuration (3-tier cascade) &#9472;&#9472;
SOURCE_CONN = spark.conf.get(
    "spark.dataplatform.source.connection",
    "jdbc:postgresql://localhost:5432/telemetry"   # dev default
)
SILVER_TABLE = "lakehouse.silver_incremental_telemetry"
BATCH_HOURS = 2
ACTIVE_THRESHOLD = 0.50  # Named constant &#8212; not inline literal

# &#9472;&#9472; Cell 3: Read Source + Tail Fetch &#9472;&#9472;
new_batch = spark.read.jdbc(
    SOURCE_CONN, "telemetry_events",
    properties={"fetchsize": "5000"}
).filter(f"event_time &gt;= NOW() - INTERVAL '{BATCH_HOURS} hours'")

# Tail records bridge the previous batch boundary
from pyspark.sql import functions as F
from pyspark.sql.window import Window

existing = spark.read.format("delta").table(SILVER_TABLE)
tails = existing.groupBy("entity_id").agg(
    F.max("event_time").alias("event_time")
)
tail_records = existing.join(tails, ["entity_id", "event_time"])

# &#9472;&#9472; Cell 4: Transform &#8212; LEAD window for end_time &#9472;&#9472;
combined = tail_records.unionByName(new_batch)
w = Window.partitionBy("entity_id").orderBy("event_time")
with_end = combined.withColumn(
    "end_time", F.lead("event_time").over(w)
)
result = with_end.filter(
    f"event_time &gt;= NOW() - INTERVAL '{BATCH_HOURS} hours'"
).cache()

# &#9472;&#9472; Cell 5: Derive status from thresholds &#9472;&#9472;
result = result.withColumn("status",
    F.when(F.col("connected") == False, F.lit("Disconnected"))
     .when(F.col("idle_ratio") &gt; ACTIVE_THRESHOLD, F.lit("Idle"))
     .when(F.col("activity_metric") &gt; 0, F.lit("Active"))
     .otherwise(F.lit("Standby"))
)

# &#9472;&#9472; Cell 6: Write &#8212; Delta Lake MERGE &#9472;&#9472;
from delta.tables import DeltaTable
target = DeltaTable.forName(spark, SILVER_TABLE)
target.alias("t").merge(
    result.alias("s"),
    "t.entity_id = s.entity_id AND t.event_time = s.event_time"
).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute()

# &#9472;&#9472; Cell 7: Cleanup &#9472;&#9472;
result.unpersist()
</code></pre></div><p>The pattern is generic. Replace <code>entity_id</code> with any entity key &#8212; asset IDs, device IDs, vehicle IDs, sensor IDs &#8212; and the tail-fetching technique works identically. The skill encodes the pattern; the developer provides the domain context. Claude Code handles the structural compliance.</p><p>After generating the notebook, you can run the skill&#8217;s validation script (<code>scripts/validate-structure.sh</code>) to confirm compliance, or invoke <code>/audit-cache</code> to verify that every <code>cache()</code> is paired with <code>unpersist()</code>. The creation skill and the audit skills form a closed loop.</p><div><hr></div><h2>04 &#183; Auto Memory &#8212; Compounding Knowledge Across Sessions</h2><p>Claude Code builds <strong>auto memory</strong> as it works &#8212; saving learnings like build commands, debugging insights, and project-specific patterns across sessions without explicit configuration. For a complex data platform, this creates a compounding knowledge loop:</p><blockquote><p><strong>How Memory Compounds</strong></p><p>After debugging an OOM crash caused by an orphaned <code>cache()</code> on constrained capacity, Claude Code saves that insight. Next time it creates or reviews a notebook, it proactively flags unmatched cache calls &#8212; not because of a rule in CLAUDE.md or a skill&#8217;s anti-pattern list, but because it learned from a real production failure.</p><p>After encountering a serving-layer write that silently failed because of a missing partition key, that debugging pattern enters Claude&#8217;s working memory. It surfaces the warning before the same mistake happens again &#8212; across all developers on the project, not just the one who fixed it originally.</p></blockquote><p>This is the strategic advantage that separates AI-assisted development from traditional tooling. A linter checks rules that were explicitly written. Skills encode patterns that were deliberately designed. Auto memory adds a third layer: patterns that were <strong>learned from experience</strong>. Every debugging session, every production incident, every code review feeds back into Claude Code&#8217;s project-specific understanding. The platform gets harder to break over time &#8212; not through more rules, but through accumulated operational wisdom.</p><blockquote><p><strong>The Three Layers of Protection</strong></p><p>Think of it as defense in depth. <strong>Skills</strong> prevent known violations at generation time. <strong>Governance audit skills</strong> catch violations that slip through in existing code. <strong>Auto memory</strong> catches the violations that nobody thought to write a rule for yet &#8212; because they have not happened before. When a new failure mode occurs and gets debugged, it enters auto memory immediately, before anyone writes a new skill or updates CLAUDE.md. The formal rule comes later; the protection starts now.</p></blockquote><div><hr></div><h2>05 &#183; Agentic Workflows &#8212; Cross-Cutting Audits at Scale</h2><p>The most powerful use of Claude Code for data platforms is not generating code &#8212; it is running cross-cutting audits that span infrastructure, application code, and documentation simultaneously. These workflows chain custom skills with bundled skills for comprehensive checks.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;78500169-ca7e-4a06-8e69-528a7096851b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown"># Full governance audit &#8212; chains custom and bundled skills
$ claude -p "Run all governance checks:
  1. /validate-serving-layer &#8212; partition keys
  2. /audit-cache &#8212; orphaned caches
  3. /check-merge-keys &#8212; MERGE key consistency
  4. /check-infra-consistency &#8212; Terraform &#8596; notebook alignment
  Then run /review on any notebook flagged as NEEDS FIX.
  Report all findings as a single markdown table with severity."

# Bulk audit across a domain using /batch
$ claude
&gt; /batch "run /audit-cache on every notebook in notebooks/telemetry/"

# Pipe deployment logs for anomaly detection
$ tail -500 pipeline-run.log | claude -p "Analyze for:
  - Failed MERGE operations
  - Serving-layer write timeouts
  - Unexpected null counts in partition columns
  - Spark OOM warnings
  Classify each as CRITICAL / WARNING / INFO"

# Recurring monitoring during deployments
$ claude
&gt; /loop 30m "Check the latest pipeline run logs for
  CRITICAL errors. Summarize and suggest a fix."
</code></pre></div><p>The workflow chains four custom governance skills, then feeds flagged notebooks into the bundled <code>/review</code> skill for general code quality analysis. The <code>/batch</code> bundled skill enables running any audit across multiple files in a single invocation &#8212; useful for domain-wide compliance checks before a release. The <code>/loop</code> skill acts as a lightweight monitoring layer during deployment windows, and the Unix-philosophy piping (<code>tail | claude</code>) integrates Claude Code into the same operational workflows that already exist in the terminal.</p><div><hr></div><h2>06 &#183; The Full Development Stack</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MRSi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MRSi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 424w, https://substackcdn.com/image/fetch/$s_!MRSi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 848w, https://substackcdn.com/image/fetch/$s_!MRSi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!MRSi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MRSi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png" width="1440" height="1440" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1440,&quot;width&quot;:1440,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:181189,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191644819?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MRSi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 424w, https://substackcdn.com/image/fetch/$s_!MRSi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 848w, https://substackcdn.com/image/fetch/$s_!MRSi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!MRSi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed7de1a9-27b5-43a6-bffd-5e4d92753b23_1440x1440.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Powered by Claude (epic feature).</figcaption></figure></div><p>Each layer builds on the previous one. CLAUDE.md provides the architectural foundation. Pipeline creation skills encode the implementation patterns. Governance audit skills verify compliance &#8212; amplified by bundled skills like <code>/review</code> and <code>/batch</code> for reach. Auto memory retains the lessons from production. And agentic workflows tie everything together into a system that actively prevents regression &#8212; not just in code, but in the cross-cutting architectural decisions that make a data platform reliable.</p><div><hr></div><h2>07 &#183; Key Takeaways</h2><p><strong>Claude Code is not a code generator &#8212; it is an architectural enforcement layer.</strong> For complex data platforms, the value is not in writing PySpark faster. It is in <strong>embedding foundational and reliable knowledge into the development workflow so that quality rules are enforced automatically</strong>, failure patterns are remembered across sessions, and cross-cutting checks run in seconds rather than hours.</p><p><strong>CLAUDE.md is a routing table, not a knowledge dump.</strong> Keep it concise, encode the rules, and use progressive disclosure for deeper context. Under 60 lines is enough for production ready pipeline platform.</p><p><strong>Pipeline creation skills prevent violations at generation time.</strong> Catching a missing partition key during code review costs hours. Preventing it with a skill that encodes the mandatory structure, supported by templates and examples, costs zero. Encode every repeatable pipeline pattern as a skill.</p><p><strong>Governance audit skills make compliance auditable and repeatable.</strong> The <code>/validate-serving-layer</code> skill catches the exact failure mode that caused days of debugging &#8212; and it runs in seconds. Every hard-won lesson from production should become a skill. Use <code>allowed-tools</code> to keep audit skills read-only and <code>context</code> to auto-load reference documentation.</p><p><strong>Auto memory creates a compounding advantage.</strong> Skills catch known patterns. Memory catches patterns that nobody thought to write a skill for yet. The more failures Claude Code sees, the harder the platform becomes to break.</p><p><strong>Cross-boundary consistency is the hardest problem.</strong> Terraform container definitions, notebook partition keys, serving-layer document schemas, and documentation must all agree. A single skill with the right <code>context</code> fields bridges infrastructure and application code &#8212; catching drift that no single-tool CI/CD pipeline can detect.</p><div><hr></div><h2>The Series</h2><ul><li><p><strong>Part I</strong> &#8212; <em><a href="https://sandrogomez.com/p/how-to-build-a-real-time-analytics">How to Build a Real-Time Analytics Platform on a Constrained Budget</a></em>.</p></li><li><p><strong>Part II</strong> &#8212; <em> <a href="https://sandrogomez.com/p/development-engine-for-complex-data">Development Engine for Complex Data Platforms</a></em>.</p></li><li><p><strong>Part III</strong> &#8212; <em><a href="https://sandrogomez.com/p/enforcing-data-quality-and-governance">Enforcing Data Quality and Governance with Claude Code</a></em>. <em>(You are here)</em></p></li></ul><div><hr></div><p><em>Claude Code &#183; Terraform &#183; PySpark &#183; Delta Lake &#183; Unified Skills &#183; Data Governance &#183; Auto Memory &#183; Agentic Workflows &#183; Platform Engineering</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro Gomez&#8217;s personal blog! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="pullquote"><p><strong>Disclaimer</strong>: Built from the ground up using documentation and diagrams from production-scale Medallion architectures. While <strong>Claude</strong> assisted in the structural organization of this post, all technical strategies and data-processing milestones are derived from my direct professional practice.</p></div>]]></content:encoded></item><item><title><![CDATA[How to Build a Real-Time Analytics Platform on a Constrained Budget (part I)]]></title><description><![CDATA[Architecture decisions, data governance patterns, and investment strategies for turning heterogeneous data streams into a unified intelligence layer &#8212; on Microsoft Fabric.]]></description><link>https://sandrogomez.com/p/how-to-build-a-real-time-analytics</link><guid isPermaLink="false">https://sandrogomez.com/p/how-to-build-a-real-time-analytics</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Sat, 21 Mar 2026 00:54:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/70cd829f-b844-4acb-8354-be4c3c6722ac_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>01 &#183; The Architectural Challenge</h2><p>Every data-intensive operation faces the same structural problem: the systems that generate data were not designed to talk to each other. Dispatch platforms export batch files on a X-hour cadence. Telemetry systems stream sensor readings every 10 minutes. GPS trackers emit continuous position data. Environmental sensors report for regulatory compliance. Operational databases accumulate millions of rows of time-series data.</p><p>Each source has its own format, cadence, latency requirements, and failure modes. The business, however, does not care about any of that. It needs a <strong>unified analytical layer</strong> that produces consistent KPIs, feeds real-time dashboards, and supports historical analysis &#8212; all on a compute budget that is not unlimited.</p><p>This is a pattern that repeats across industries: manufacturing, logistics, energy, mining, agriculture, insurance, financial, etc. The specific data sources change, but the architectural challenge is the same &#8212; <strong>how do you turn fragmented, heterogeneous data streams into a single source of truth without building an expensive monolith?</strong></p><blockquote><p><strong>The Real Constraint</strong></p><p>The hardest problem is not ingesting the data. It is maintaining <strong>consistency</strong> across all consumers. When a KPI is computed in a Spark notebook, displayed in a Power BI dashboard, and served through a REST API, all three must produce the same number. Business constants, exclusion rules, and threshold logic must be identical everywhere &#8212; and they must survive team changes, late-arriving data, and pipeline failures.</p></blockquote><div><hr></div><h2>02 &#183; Architecture Strategy: The Medallion Pattern</h2><p>The medallion architecture is not new. But the value is not in the pattern itself &#8212; it is in the discipline of separating concerns cleanly. Each layer has a specific responsibility, and no layer is allowed to bypass the one before it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J1Dn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J1Dn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 424w, https://substackcdn.com/image/fetch/$s_!J1Dn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 848w, https://substackcdn.com/image/fetch/$s_!J1Dn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 1272w, https://substackcdn.com/image/fetch/$s_!J1Dn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J1Dn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png" width="1456" height="526" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:526,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2107146,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191628399?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!J1Dn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 424w, https://substackcdn.com/image/fetch/$s_!J1Dn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 848w, https://substackcdn.com/image/fetch/$s_!J1Dn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 1272w, https://substackcdn.com/image/fetch/$s_!J1Dn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F062712ec-ed81-415d-9b52-12810c72db2d_6313x2279.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Bronze</strong> is a pure landing zone. Data arrives exactly as-is &#8212; no transformations, no cleaning, no schema enforcement. This is the safety net: if anything goes wrong downstream, the raw data is always available for replay.</p><p><strong>Silver</strong> is where trust is established. Schema enforcement, data type validation, deduplication, and ACID-compliant writes (via Delta Lake MERGE) happen here. Every record that enters Silver has passed a set of validation rules. This is the layer where domain-specific checks &#8212; geographic bounding boxes, valid ranges, referential integrity &#8212; are applied at ingestion time, not after the fact.</p><p><strong>Gold</strong> is the business layer. Aggregations, enrichment with dimension tables, KPI computation, and industry-standard metrics are calculated here. This is the only layer that consumers should ever query directly.</p><p><strong>Serving</strong> is the delivery mechanism. Cosmos DB provides sub-second latency for real-time dashboards. Power BI connects directly to Gold tables for historical reporting. REST APIs expose KPIs to external systems.</p><blockquote><p><strong>Why This Matters Strategically</strong></p><p>The medallion pattern is fundamentally a <strong>risk management architecture</strong>. Each layer isolates a different kind of failure. Bronze absorbs source-system instability. Silver prevents bad data from contaminating analytics. Gold ensures business logic is computed once and shared everywhere. When something breaks &#8212; and in a 24/7 operation, it will &#8212; the blast radius is contained.</p></blockquote><div><hr></div><h2>03 &#183; Three Ingestion Patterns for Different Data Behaviors</h2><p>Not all data behaves the same way. A shift report that arrives every 12 hours requires a fundamentally different ingestion strategy than a sensor reading that arrives every 10 minutes, or a database that accumulates millions of rows of time-series data. Trying to force all three through the same pipeline creates fragile, overloaded systems.</p><p>I want to share three distinct ingestion patterns proved by my self in large data solutions, each designed for a specific data behavior:</p><blockquote><p><strong>Pattern 1 &#8212; Orchestrated Batch</strong></p><p>For periodic, structured exports: an <strong>orchestrator notebook</strong> acts as the single entry point. It resolves all secrets once, reads all source files once into shared Spark temp views, then runs child notebooks sequentially within a single Spark session. This reduces cold start overhead by approximately 60% and guarantees that all child notebooks consume identical input data. Each child can still run independently in development mode by falling back to its own file discovery logic.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oVr0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oVr0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 424w, https://substackcdn.com/image/fetch/$s_!oVr0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 848w, https://substackcdn.com/image/fetch/$s_!oVr0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 1272w, https://substackcdn.com/image/fetch/$s_!oVr0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oVr0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png" width="1456" height="350" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:350,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2463721,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191628399?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oVr0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 424w, https://substackcdn.com/image/fetch/$s_!oVr0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 848w, https://substackcdn.com/image/fetch/$s_!oVr0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 1272w, https://substackcdn.com/image/fetch/$s_!oVr0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed2624b6-5beb-448b-bcc0-20d33a84c1cd_7314x1760.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><blockquote><p><strong>Pattern 2 &#8212; Hybrid Event-Driven + Scheduled</strong></p><p>For multiple independent streams with different formats and frequencies: each stream gets its own isolated notebook with three execution modes. <strong>Event-driven</strong> (triggered by new files, sub-5-minute latency) handles 90% of normal operations. <strong>Scheduled</strong> (every 1&#8211;4 hours, using time-based path generation instead of recursive directory listing) provides self-healing recovery. <strong>Backfill</strong> (full recursive scan, manual trigger) supports initial loads. The scheduled mode uses generated path patterns rather than listing thousands of folders, so performance stays constant regardless of total data volume.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!f-cp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f-cp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 424w, https://substackcdn.com/image/fetch/$s_!f-cp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 848w, https://substackcdn.com/image/fetch/$s_!f-cp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 1272w, https://substackcdn.com/image/fetch/$s_!f-cp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f-cp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png" width="1456" height="1079" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1079,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1156137,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191628399?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!f-cp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 424w, https://substackcdn.com/image/fetch/$s_!f-cp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 848w, https://substackcdn.com/image/fetch/$s_!f-cp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 1272w, https://substackcdn.com/image/fetch/$s_!f-cp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99bff42d-e4df-468d-99e7-41eb3a06d092_2806x2080.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><blockquote><p><strong>Pattern 3 &#8212; Incremental Replication with Tail Fetching</strong></p><p>For continuously growing source databases: the pipeline fetches new records from the source, but also retrieves the <strong>tail record per entity</strong> from the existing Delta Lake table. These tails are unioned with the new batch before applying window functions (LEAD) to compute derived fields like end times. This bridges batch boundaries without reprocessing historical data, keeping each run&#8217;s scope minimal while producing a complete, gapless time series.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qvqL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qvqL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 424w, https://substackcdn.com/image/fetch/$s_!qvqL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 848w, https://substackcdn.com/image/fetch/$s_!qvqL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 1272w, https://substackcdn.com/image/fetch/$s_!qvqL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qvqL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png" width="1456" height="385" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:385,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1589993,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191628399?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qvqL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 424w, https://substackcdn.com/image/fetch/$s_!qvqL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 848w, https://substackcdn.com/image/fetch/$s_!qvqL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 1272w, https://substackcdn.com/image/fetch/$s_!qvqL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6f680c-012c-40d0-931a-c8d0a99642e9_5479x1449.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>The key insight:</strong> these three patterns are <strong>transferable</strong>. They are not specific to any industry or vendor. An orchestrated batch pattern works the same way whether it processes manufacturing production runs or logistics delivery cycles. The hybrid event/scheduled pattern applies anywhere you have multiple independent data sources with different cadences. And tail fetching solves the incremental time-series problem regardless of the source database technology.</p><div><hr></div><h2>04 &#183; Data Governance as Engineering Discipline</h2><p>Governance in a real-time analytics platform cannot be a separate workstream. It has to be embedded in every write operation, every pipeline structure, and every deployment. Here is the framework that makes that practical:</p><p><strong>Idempotency everywhere.</strong> Every write operation uses Delta Lake MERGE (UPSERT). Re-running any pipeline for any time window produces identical results without creating duplicates. When pipelines run on schedules, they will occasionally overlap, retry, or be manually re-triggered. Every write must be safe to repeat. This is the foundation of data trust in any batch or hybrid processing system.</p><p><strong>Validation at ingestion, not downstream.</strong> Bad data that enters the Silver layer will propagate to every consumer. Geographic coordinates outside valid ranges are rejected on arrival. Geometry data is validated and centroids are extracted during ingestion. Alert thresholds are computed at write time with classification logic that cannot be manually overridden. The principle: if a record passes Silver, it is trustworthy.</p><p><strong>Configuration hierarchy, not hardcoded values.</strong> All pipelines use a 3-tier cascade: Key Vault &#8594; Spark Config &#8594; Default Value. This supports multiple environments (dev/UAT/prod) without code changes and makes standalone notebook development possible without infrastructure access.</p><p><strong>Six Quality Rules (at least) &#8212; Enforced Repo-Wide</strong></p><p>These are not guidelines. They are deployment blockers: </p><ol><li><p>Every environment config must have a default value.</p></li><li><p>Every document in the serving layer must carry its partition key.</p></li><li><p>All fact-to-dimension joins must be LEFT joins with count guards (depends on use case).</p></li><li><p>Every <code>cache()</code> must be paired with <code>unpersist()</code> to prevent memory exhaustion on shared sessions.</p></li><li><p>Named constants replace hardcoded literals everywhere.</p></li><li><p>Imports stay at the top of each module. </p></li></ol><div class="pullquote"><p><strong>Each rule was learned from a production failure &#8212; not derived from theoretical best practices.</strong></p></div><p><strong>Documentation as engineering.</strong> Every code change requires a documentation update in the same commit. User-facing documentation must consider all the roles involved (Data engineers don&#8217;t speak data scientists&#8217; language). Technical context files include mandatory checklists. Incomplete documentation equals incomplete work &#8212; not a nice-to-have that gets deferred.</p><div><hr></div><h2>05 &#183; Budget Strategy: Running Pipelines on Minimal Compute</h2><p>Architecture discussions often ignore the budget constraint. But the compute budget is the most powerful forcing function for good engineering. When you have unlimited resources, you can afford sloppy scheduling, redundant processing, and unoptimized pipelines. When you have a strict ceiling, every design decision matters.</p><p>For example if platform runs on a <strong>Fabric F4 capacity</strong> &#8212; one of the smallest SKUs available &#8212; with a ceiling of 4 Capacity Units. The entire scheduling strategy should be designed around staying within that limit.</p><p>The budget constraint is not a limitation &#8212; it is a design principle. It forces incremental processing (no full table reprocessing), shared Spark sessions (no redundant cold starts), and staggered scheduling (no overlapping compute bursts). These same patterns reduce cost at any scale, not just on an F4.</p><div><hr></div><h2>06 &#183; Investment Strategy: CAPEX vs. OPEX in Modern Data Platforms</h2><p>The traditional approach to data infrastructure treats it as a capital expenditure: buy servers, license software, build a data center, amortize over 3&#8211;5 years. This model has a fundamental flaw for analytics platforms &#8212; <strong>you are locking in capacity before you know what the platform needs to do</strong>.</p><p>Cloud-native, consumption-based platforms flip this model. The entire compute cost becomes OPEX &#8212; adjustable month to month, tied to actual usage rather than projected capacity. This has three strategic implications:</p><blockquote><p><strong>1. Prove Value Before Scaling</strong></p><p>A small-capacity SKU costs a fraction of what traditional on-premise infrastructure requires. The platform can run in production, serve real dashboards, and demonstrate measurable ROI &#8212; all before a single scaling decision needs to be made. Investment follows validated results, not projected ones.</p><p><strong>2. Granular Scaling, Not Step-Function Upgrades</strong></p><p>Scaling from F4 to F8, F16, or F64 is a configuration change, not a procurement cycle. More importantly, the architecture is designed so that scaling does not require re-engineering. Staggered scheduling works the same way at any capacity. The orchestrator pattern, incremental processing, and tail fetching all produce constant-scope workloads regardless of data growth. The platform scales by adding capacity, not by rewriting pipelines.</p><p><strong>3. Reversible Decisions</strong></p><p>If a processing domain turns out to deliver less value than expected, its pipelines can be decommissioned and the capacity reclaimed immediately. With CAPEX infrastructure, <strong>sunk costs create pressure to keep using systems that have outlived their usefulness</strong>. With OPEX, every component must continuously justify its compute consumption.</p></blockquote><p>This does not mean CAPEX has no role. For extremely stable, high-volume workloads where utilization is predictable, reserved capacity or committed-use discounts can reduce per-unit costs significantly. The strategic approach is to <strong>start OPEX, prove value, then selectively convert proven workloads to reserved capacity</strong> as their patterns stabilize. This minimizes risk at every stage.</p><div><hr></div><h2>07 &#183; Scalability Path and ROI</h2><p>This architecture was designed with explicit scalability mechanisms &#8212; patterns that support growth without requiring re-architecture:</p><p><strong>Staggered scheduling absorbs new pipelines.</strong> Adding new data streams does not require more compute &#8212; just more precise time-slot management. The same capacity budget can serve additional pipelines by adjusting offsets and frequency windows.</p><p><strong>The orchestrator pattern reduces marginal cost.</strong> Adding a new analytical notebook to an existing processing domain requires minimal incremental compute, because secrets, file reads, and Spark sessions are already shared. The overhead per notebook decreases as the domain grows.</p><p><strong>Incremental processing keeps costs constant.</strong> Tail fetching and Delta Lake MERGE ensure that each run processes only new and updated records. Whether the historical table holds 1 million or 50 million rows, the per-cycle cost stays the same.</p><p><strong>The medallion pattern supports new consumers without new processing.</strong> Once data reaches Gold, any number of serving endpoints &#8212; new dashboards, new APIs, new reporting tools &#8212; can consume it without touching the processing pipelines. The marginal cost of a new consumer is nearly zero.</p><blockquote><p><strong>The ROI Equation</strong></p><p>The return on a real-time analytics platform is not in the infrastructure &#8212; it is in the decisions the infrastructure enables. When KPIs are computed consistently and served in near real-time, the business can act on operational signals faster: identifying underperforming assets, reducing unnecessary maintenance cycles, optimizing resource allocation. In capital-intensive industries, even a small percentage improvement in asset utilization can pay for the entire platform many times over. The architecture&#8217;s job is to make those decisions trustworthy, fast, and affordable.</p></blockquote><div><hr></div><h2>08 &#183; Key Takeaways</h2><p><strong>Separate concerns cleanly.</strong> The medallion pattern is not a buzzword &#8212; it is a risk management architecture. Each layer absorbs a different failure mode. Bronze absorbs source instability, Silver enforces trust, Gold computes business logic once, and the serving layer delivers it everywhere.</p><p><strong>Match ingestion patterns to data behavior.</strong> Orchestrated batch, hybrid event/scheduled, and incremental replication with tail fetching are three distinct patterns for three distinct data behaviors. Forcing one pattern onto all data sources creates fragility.</p><p><strong>Embed governance in the pipeline, not beside it.</strong> Idempotent writes, validation at ingestion, and enforced quality rules are not polish added after the platform works &#8212; they are the reason the platform works. Without them, every new pipeline becomes a liability.</p><p><strong>Use the budget as a design principle.</strong> Constraints force better engineering. Staggered scheduling, shared sessions, and incremental processing are not compromises &#8212; they are patterns that reduce cost at any scale.</p><p><strong>Start OPEX, prove value, then optimize.</strong> Cloud-native consumption models eliminate the need to justify large upfront investments. Prove the platform delivers measurable results on minimal compute, then scale with confidence.</p><p><strong>Invest in transferable patterns, not vendor lock-in.</strong> The orchestrator pattern, tail fetching, hybrid ingestion, and the medallion architecture work on Fabric, Databricks, Snowflake, or any modern lakehouse platform. The engineering discipline is the asset &#8212; the vendor is the vehicle.</p><div><hr></div><p><em>Medallion Architecture &#183; Data Governance &#183; CAPEX/OPEX &#183; Delta Lake &#183; Microsoft Fabric Apache Spark &#183; Cosmos DB &#183; Incremental ETL &#183; Platform Strategy &#183; Budget Optimization</em></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro Gomez&#8217;s personal blog! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Compartir Sandro Gomez&#8217;s personal blog&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://sandrogomez.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Compartir Sandro Gomez&#8217;s personal blog</span></a></p><p></p><div class="pullquote"><p><strong>Disclaimer:</strong> Built from the ground up using documentation and diagrams from production-scale Medallion architectures. While <strong>Claude</strong> assisted in the structural organization of this post, all technical strategies and data-processing milestones are derived from my direct professional practice.</p></div>]]></content:encoded></item><item><title><![CDATA[The AI change the game... for ever.]]></title><description><![CDATA[Let&#8217;s to talk about real impact in dev productivity through AI adoption.]]></description><link>https://sandrogomez.com/p/the-ai-change-the-game-for-ever</link><guid isPermaLink="false">https://sandrogomez.com/p/the-ai-change-the-game-for-ever</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Thu, 19 Mar 2026 04:13:15 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/279801ee-96e8-45b2-8cc8-82952e53d310_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Scenario</h2><p>Fifty-five microservices running across three environments are essential for critical operations, processing millions of events, messages, and records. </p><h2>The challenge</h2><p>The primary challenge is to unify the logging systems and standards to achieve comprehensive observability, enabling the detection of service deterioration, errors, and potential failures.</p><h2>The Enabler</h2><p><strong><a href="https://code.claude.com/docs/es/overview">Claude Code</a> </strong></p><h2>The result</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YC2-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YC2-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 424w, https://substackcdn.com/image/fetch/$s_!YC2-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 848w, https://substackcdn.com/image/fetch/$s_!YC2-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 1272w, https://substackcdn.com/image/fetch/$s_!YC2-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YC2-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png" width="1456" height="522" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:522,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:159053,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191441137?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YC2-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 424w, https://substackcdn.com/image/fetch/$s_!YC2-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 848w, https://substackcdn.com/image/fetch/$s_!YC2-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 1272w, https://substackcdn.com/image/fetch/$s_!YC2-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6415acb5-1179-4ecf-a00e-55aeb961b773_2538x910.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>The investment</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!14QE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!14QE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 424w, https://substackcdn.com/image/fetch/$s_!14QE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 848w, https://substackcdn.com/image/fetch/$s_!14QE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 1272w, https://substackcdn.com/image/fetch/$s_!14QE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!14QE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png" width="1456" height="501" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:501,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:242241,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191441137?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!14QE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 424w, https://substackcdn.com/image/fetch/$s_!14QE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 848w, https://substackcdn.com/image/fetch/$s_!14QE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 1272w, https://substackcdn.com/image/fetch/$s_!14QE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ab40d90-8cfd-41ac-a6fa-1e3240ad7835_2576x886.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>The Impact</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QsYY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QsYY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 424w, https://substackcdn.com/image/fetch/$s_!QsYY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 848w, https://substackcdn.com/image/fetch/$s_!QsYY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 1272w, https://substackcdn.com/image/fetch/$s_!QsYY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QsYY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png" width="1456" height="894" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:894,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:496727,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://sandrogomez.com/i/191441137?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QsYY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 424w, https://substackcdn.com/image/fetch/$s_!QsYY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 848w, https://substackcdn.com/image/fetch/$s_!QsYY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 1272w, https://substackcdn.com/image/fetch/$s_!QsYY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51cc2e98-9a89-4dfc-b707-f2086f34df72_2556x1570.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Final Thoughs</h2><blockquote><p><strong>Be serious&#8230; AI is changing the game.</strong></p></blockquote><p></p><p><strong>Are you interested in the real game of AI? Let&#8217;s talk&#8230;</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Suscribirse&quot;,&quot;language&quot;:&quot;es&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#161;Gracias por leer Sandro Gomez&#8217;s personal blog! Suscr&#237;bete gratis para recibir nuevos posts y apoyar mi trabajo.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Escribe tu correo electr&#243;nico..." tabindex="-1"><input type="submit" class="button primary" value="Suscribirse"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[¿Cómo indentificar un agilista?]]></title><description><![CDATA[Un Agilista impulsa equipos din&#225;micos, enfocados en entregar valor de forma r&#225;pida y continua, adapt&#225;ndose a los cambios para lograr resultados extraordinarios.]]></description><link>https://sandrogomez.com/p/como-indentificar-un-agilista</link><guid isPermaLink="false">https://sandrogomez.com/p/como-indentificar-un-agilista</guid><dc:creator><![CDATA[Sandro Gomez]]></dc:creator><pubDate>Wed, 02 Oct 2024 23:05:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!pkWG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pkWG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pkWG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!pkWG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!pkWG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!pkWG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pkWG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:308011,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pkWG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!pkWG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!pkWG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!pkWG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5c1d50f-18c0-42df-b9e6-4a9562590545_1792x1024.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Un &#8220;Agilista&#8221; es un t&#233;rmino utilizado para describir a alguien que practica o aboga por metodolog&#237;as &#225;giles en la gesti&#243;n de proyectos y el desarrollo de software. Las metodolog&#237;as &#225;giles y los diferentes marcos de trabajo, enfatizan la flexibilidad, la mejora continua y la capacidad de adaptarse a los requisitos en contextos cambiantes.</p><p>Algunas caracter&#237;sticas clave que definen a un Agilista incluyen:</p><h2><strong>Colaboraci&#243;n</strong></h2><p>Los agilistas priorizan el trabajo en equipo y la colaboraci&#243;n entre los miembros del equipo y las partes interesadas. Facilitan la comunicaci&#243;n para garantizar que todos est&#233;n alineados y que los objetivos del proyecto se entiendan claramente.</p><h2><strong>Adaptabilidad y flexibilidad</strong></h2><p>Defienden la adaptabilidad y alientan a los equipos a responder a los cambios en lugar de seguir un plan preestablecido. Esto refleja el principio &#225;gil central de responder al cambio en lugar de seguir un plan.</p><h2><strong>Desarrollo Iterativo</strong></h2><p>Los agilistas apoyan el desarrollo iterativo, donde los proyectos se dividen en segmentos manejables (iteraciones), lo que permite a los equipos <strong>reevaluar y ajustar con frecuencia su direcci&#243;n</strong>.</p><h2><strong>Enfoque centrado en el cliente</strong></h2><p>Mantienen un fuerte enfoque en entregar valor al cliente, a menudo involucr&#225;ndolo durante todo el proceso de desarrollo para garantizar que el producto final satisfaga sus necesidades y expectativas.</p><h2><strong>Mejora continua</strong></h2><p>Un agilista cree en la mejora constante de procesos, productos y pr&#225;cticas a trav&#233;s de ciclos regulares de reflexi&#243;n y adaptaci&#243;n.</p><h2><strong>Liderazgo y facilitaci&#243;n</strong></h2><p>En los diferentes roles que asumen, los Agilistas <strong>act&#250;an como facilitadores en lugar de gerentes tradicionales</strong>, ayudando a los equipos a auto-organizarse y <strong>crear un entorno propicio para un trabajo eficaz y un aprendizaje continuo</strong>.</p><h1><strong>Comentarios</strong></h1><p>Compa&#241;&#237;as que abrazan los principios y valores de la agilidad, se destacan como organizaciones resilientes a los cambios y desaf&#237;os emergentes del mundo actual. Destaca la cultura centrada en las personas creando espacios seguros de experimentaci&#243;n e innovaci&#243;n. Con enfoque &#250;nico en sus clientes y <em>shareholders </em>son h&#225;biles en entregar valor de forma consistente y oportuna (<a href="https://www.mckinsey.com/featured-insights/mckinsey-explainers/what-is-agile">What is agile?</a> &#8212; Mckinsey).</p><h1><strong>Key Takeaways</strong></h1><p>Algunas recomendaciones</p><ul><li><p>Entender los principios &#225;giles y los <em>gaps</em> de tu organizaci&#243;n.</p></li><li><p>Documentate acerca de la agilidad, sus origenes, evoluci&#243;n e implementaci&#243;n (buenas y malas pr&#225;cticas).</p></li><li><p>Formaliza tus conocimientos buscando entrenamiento en el rol que mejor te defina.</p></li><li><p>Lee mucho y busca ayuda en comunidades y foros.</p></li></ul><p>Te comparto un par de libros que te ayudar&#225;n en el viaje.</p><ol><li><p><a href="https://www.amazon.com/Age-Agile-Smart-Companies-Transforming-ebook/dp/B072J5XPTP/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.YtIrXYymlBEhh9BAfF4PgQ.sbGYnHoYREb3ejN83Q5uWKnQxq9KqXHDBeVYrUVyjHw&amp;qid=1715052562&amp;sr=1-1">The Age of Agile</a></p></li><li><p><a href="https://www.amazon.com/Agile-Transformation-Structures-Processes-Mindsets/dp/0749497475">Agile Transformation: Structures, Processes and Mindsets for the Digital Age</a></p></li><li><p><a href="https://a.co/d/3rWHWaz">Lean Change Management</a></p></li><li><p><a href="https://a.co/d/5Sjy6Mc">Agile Change Management</a></p></li><li><p><a href="https://a.co/d/0RTuFTW">Succeding with Agile</a></p></li><li><p><a href="https://a.co/d/39BfVi7">Agile Estimating and Planning</a></p></li></ol><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sandrogomez.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Sandro&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>