Qué es el blast radius: lo que un pull request toca fuera del diff
El blast radius es el código al que llega un cambio fuera del diff. Con un pull request real, te mostramos cómo encontrarlo en el código, sin dibujar flechas falsas.
Resumen. El blast radius (radio de impacto) es el código al que llega un cambio fuera de sí mismo: los archivos que llaman al código modificado o lo importan. Este artículo explica cómo encontrar el radio de impacto de un pull request solo a partir del código, sin usar un modelo. También explica por qué buscar coincidencias por nombre dibuja flechas falsas y cómo convertir el resultado en un diagrama en GitHub. Comprobamos el comportamiento de cada herramienta en su propia documentación el 14 de octubre de 2026. El ejemplo es un pull request ya fusionado de la biblioteca requests.
- El diff no muestra quién llama al código. Muestra las líneas que cambiaron, no los archivos que las usan. En nuestro ejemplo cambian dos archivos, y otros 9 archivos dependen de ellos.
- Buscar por nombre dibuja flechas falsas. Encontramos cuatro tipos en la salida real: otra definición con el mismo nombre, un comentario que solo menciona el nombre, una segunda copia del árbol y un import enlazado al archivo equivocado.
- Solo se dibuja una flecha si el import apunta al archivo modificado. Pocas flechas seguras valen más que muchas que el lector tenga que comprobar una por una.
- Si no se pudo leer todo, no hay diagrama. Un diagrama a medias da a entender que «nadie llama a este código».
¿Qué es el blast radius?
El término viene de la ingeniería de infraestructura y describe hasta dónde se extiende un fallo. La guía de AWS sobre arquitectura basada en celdas explica que dividir el sistema en celdas aisladas entre sí reduce el blast radius. Y añade que eso ayuda no solo con el tráfico, sino también al desplegar una funcionalidad nueva o una corrección de errores (fuente).
En la revisión de código la pregunta es más concreta: fuera de este pull request, ¿quién llama o importa el código que cambia? Si cambia el tipo de retorno de una función, todos los sitios que la usan se ven afectados, así que quien revisa tiene que tenerlos en cuenta. Este tema también se busca como «change impact analysis» (análisis del impacto de un cambio).
En este artículo limitamos el radio de impacto a su anillo más cercano: los archivos que llaman directamente al archivo modificado o lo importan. Para dibujar ese diagrama solo con flechas reales hacen falta cuatro reglas.

Lo que el diff no muestra
Cuando abres un pull request, GitHub te muestra los archivos y las líneas que cambiaron. Los archivos que no cambiaron pero usan el código modificado no están en esa pantalla; quien revisa tiene que acordarse de ellos.
Un ejemplo real: el pull request 7441 de la biblioteca requests cambia dos archivos, _types.py y models.py, y en el diff solo aparecen esos dos. Al recorrer el árbol en el último commit del pull request, encontramos otros 9 archivos que los usan. Por ejemplo, sessions.py y adapters.py usan directamente la clase PreparedRequest de models.py, así que un cambio en esa clase puede alterar también el comportamiento de esos dos archivos.
El resto del artículo cuenta cómo encontramos ese número y por qué hay flechas que no dibujamos a propósito.
Tres formas habituales de encontrar los llamadores
- Búsqueda de texto.
git grep -w nombreencuentra cada línea en la que el nombre aparece como palabra completa (documentación). Es rápida y no necesita configuración. Pero también encuentra el nombre en comentarios, en cadenas de texto o en otras funciones que se llaman igual; te toca a ti distinguir cuáles son llamadas reales. - Servidor de lenguaje. «Find All References» en el editor es la petición
textDocument/referencesdel Language Server Protocol: le pide al servidor de lenguaje todas las referencias del proyecto al símbolo que está bajo el cursor (especificación). El resultado es exacto, pero vale para un solo símbolo cada vez y exige que el proyecto esté configurado en el editor. La navegación de código de GitHub en el navegador, en cambio, usa tree-sitter y, según su propia documentación, recorre todas las definiciones y referencias de un repositorio para encontrar las entidades con un nombre dado (documentación). Es decir, busca por nombre. - Herramientas de grafo de llamadas. Herramientas como pyan para Python o madge para JavaScript generan el grafo de todo el repositorio. pyan describe su propio análisis como «bastante superficial» (fuente); madge, por su parte, no dibuja las llamadas a funciones sino las dependencias entre módulos (fuente). Las dos miran todo el repositorio, no un pull request, y su resultado no cabe en un comentario de revisión.

Para un pull request hace falta algo intermedio: un diagrama tan exacto como el servidor de lenguaje, tan rápido como la búsqueda de texto y limitado al entorno de los archivos modificados. Para lograrlo hay que seguir la línea del import, no el nombre.
Cuatro flechas falsas que encontramos en la salida real
Al escribir el paso de diffox que dibuja el radio de impacto de un pull request, revisamos a mano la salida de las primeras versiones y encontramos cuatro tipos de flecha falsa. Cada uno dio lugar a una regla:
- Un nombre definido en varios sitios. Una función auxiliar con el mismo nombre estaba definida en tres herramientas distintas, y el llamador de una se dibujó como llamador de otra. Regla: no se dibuja ninguna flecha para un nombre que no esté definido exactamente una vez en todo el árbol.
- Una segunda copia del árbol. Un git worktree dentro del repositorio era una copia de todo el árbol; dos tercios de lo que encontró la primera ejecución venían de ahí. Regla: no se entra en carpetas cuyo nombre empieza por un punto.
- Una línea que solo menciona el nombre. Una línea de comentario citaba el nombre de la función como ejemplo. Regla: solo se lee el código en sí; después de quitar los comentarios y las cadenas, tiene que quedar una llamada o un import.
- Un import enlazado al archivo equivocado. La línea
from werkzeug.exceptions import NotFoundse dibujó como llamadora del propioexceptions.pydel repositorio, solo porque los dos archivos se llamaban igual. Regla: solo se dibuja una flecha si la línea de import del llamador apunta al propio archivo modificado. Un import relativo se resuelve calculando la ruta; los demás se enlazan a un único archivo mirando los archivos del árbol.
La cuarta regla tiene un precio: un llamador cuyo import no se puede seguir no entra en el diagrama. En Go y en Ruby el import no vincula ningún nombre, así que los archivos en esos lenguajes no tienen flechas; un método llamado a través de un objeto (obj.x()) tampoco se enlaza a un archivo. Una flecha que falta no le cuesta nada al lector. Una flecha falsa, en cambio, le hace desconfiar del resto del diagrama.
Cómo mantener el diagrama legible
En un repositorio real, el número de llamadores crece rápido. Dos cosas ayudan.
- Deja fuera los tests. En nuestro propio repositorio, 16 de las 19 flechas que dibujó la primera versión venían de archivos de test. «Tus tests llaman a esta función» no es algo que necesite ver quien abre el pull request. Distingue los tests por su ruta, no por su contenido: la carpeta
tests/,test_*.py,*.test.tsy similares. Cuánto pesa esto depende del repositorio: en el ejemplo de requests, contar los tests habría añadido un solo archivo. - Limita el número de cajas y menciona el resto. Nadie puede leer un diagrama de cuarenta cajas, y uno que no avisa de que está recortado parece completo. Nosotros dibujamos como máximo 8 cajas y 6 llamadores por archivo modificado, y contamos el resto. En el ejemplo de requests se dibujaron 6 de los 9 archivos, y los 3 restantes se mencionan en una sola frase bajo el diagrama.
Cómo acelerar la búsqueda en cambios grandes
La forma más directa de encontrar los llamadores es buscar \bNOMBRE\b en cada línea del árbol para cada nombre que definen los archivos modificados. Un cambio grande define cientos de nombres; en un árbol de cientos de archivos, eso son millones de búsquedas con regex. En un pull request grande de nuestro propio repositorio, este paso lanzó 19,1 millones de búsquedas y, en el servidor, el diagrama superó su límite de 20 segundos. Dos cambios reducen el tiempo:
- Filtra primero los candidatos. Un archivo que nunca menciona como palabra el nombre del archivo modificado no puede importarlo, porque toda línea de import, como
from service.app import xorequire("./app"), incluye como palabra la última parte de la ruta. En nuestra herramienta anterior, indexar el árbol entero llevaba 51 segundos con 299 archivos; este filtro lo bajó a 38 archivos y 3,2 segundos, sin perder ninguna flecha. - Busca por línea, no por nombre. Según la documentación de Python,
\bes el límite entre un carácter de palabra y uno que no lo es (documentación). Por eso, para un nombre formado solo por caracteres de palabra,\bNOMBRE\bcoincide solo si una de las palabras de la línea es exactamente ese nombre. Un únicofindallpor línea responde a la vez por todos los nombres, y solo queda hacer una intersección de conjuntos. Los nombres con otros caracteres, como$fooovalid?, se siguen buscando con su propio patrón.
import re
WORD = re.compile(r"\w+")
def hits(lines, names):
"""Los nombres que aparecen en cada línea: un solo findall por línea en lugar de una regex por nombre."""
wanted = set(names)
for number, line in enumerate(lines, 1):
found = wanted.intersection(WORD.findall(line))
if found:
yield number, foundCuánto se gana depende de cuántos nombres se busquen. Medimos las dos formas sobre los mismos árboles y en la misma máquina, y las dos encontraron exactamente lo mismo cada vez:

En Django, cuando cambia un solo archivo grande (127 nombres), la diferencia entre las dos formas es pequeña. Cuando el cambio se reparte entre los cinco archivos más grandes (577 nombres), buscar por línea es 3,9 veces más rápido; en nuestro propio pull request (570 nombres), 8,2 veces. Así que este cambio no acelera todas las revisiones: cuando crece el número de nombres, hace que el diagrama vuelva a caber en su límite de tiempo. El cuello de botella no lo adivinamos, lo encontramos con un profiler: la mayor parte del tiempo se iba en un solo bucle.
Cuándo no dibujar el diagrama
Si un recorrido choca con un límite de tiempo o de tamaño y se detiene a mitad del árbol, lo que sale no es una muestra de los llamadores. Un archivo que no se leyó no tiene llamadores en el diagrama, y eso parece «nadie lo llama». Por eso, en estos casos no dibujamos nada:
- Se acabó el tiempo. El recorrido y el índice tienen que terminar dentro de un límite de tiempo; en nuestro caso, 20 segundos.
- No se pudo leer un archivo modificado. Es demasiado grande, es un enlace simbólico o no es un archivo normal.
- Se superó un límite. El número de archivos leídos, el tamaño total o el número de nombres buscados superó su umbral.
- No hay llamadores. Una caja sin flechas sugiere un aislamiento que los datos no respaldan.
No mostrarle nada al lector es mejor que mostrarle algo falso. Eso sí, el motivo por el que no se dibujó el diagrama tiene que quedar en los logs: solo ahí se ve si fue un error o una parada esperada.
Mostrar el diagrama en GitHub con Mermaid
La forma más fácil de mostrar el diagrama es Mermaid. Según la documentación de GitHub, los diagramas se renderizan en issues, discusiones, pull requests, wikis y archivos Markdown; basta con escribir la sintaxis de Mermaid en un bloque de código con la etiqueta de lenguaje mermaid (documentación).
El diagrama del ejemplo de requests, tal como se escribe en un comentario de pull request:
```mermaid
flowchart LR
n0["_types.py"]:::changed
n1("utils.py")
n2("adapters.py")
n3("cookies.py")
n4("sessions.py")
n5["models.py"]:::changed
n6("__init__.py")
n7("exceptions.py")
n1 -.->|"SupportsItems"| n0
n2 -.->|"is_prepared"| n0
n3 -.->|"is_prepared"| n0
n4 -.->|"is_prepared"| n0
n6 -.->|"Request, PreparedRequest +1"| n5
n7 -.->|"Request, PreparedRequest +1"| n5
n4 -->|"Request, PreparedRequest +1"| n5
n1 -.->|"Request, PreparedRequest +1"| n5
n2 -->|"PreparedRequest, Response"| n5
classDef changed stroke:#3a6b8b,stroke-width:2px
```![EJEMPLO. Cuatro partes, un diagrama. comentario de pull request: flowchart LR / n0["_types.py"]:::changed / n5["models.py"]:::changed / n4("sessions.py") / n4 -->|"PreparedRequest"| n5 / n4 -.->|"is_prepared"| n0 / classDef changed stroke-width:2px. :::changed: Archivo modificado, marco propio. -->: Continua: al menos una llamada. -.->: Discontinua: solo import. |"nombre"|: Nombres usados, sobre la flecha.](/blog/img/blast-radius-in-software-engineering-mermaid-es.webp?v=b5481c06c2c2ed0e)
Tres pequeñas decisiones hacen legible el diagrama. Los archivos modificados se marcan con un marco propio. Sobre la flecha se escriben los nombres que se usan; a partir del tercero, se resumen en un número como «+1». Si un archivo solo importa el archivo modificado y no se encontró ninguna llamada directa, su flecha es discontinua. Y una sola frase bajo el diagrama dice qué quedó fuera.
El radio de impacto en diffox
Cada vez que diffox revisa un pull request, vuelve a ejecutar este paso sobre el último commit. Si encuentra llamadores fuera del diff, añade a su comentario de resumen un diagrama Mermaid con el título «Qué toca este cambio». Las reglas son las de este artículo: sin modelo, solo flechas cuyo import apunta al archivo modificado, sin tests, 8 cajas como máximo, un límite de 20 segundos y, si el recorrido no está completo, no hay diagrama. Funciona con Python, JavaScript/TypeScript y Java. Si no quieres el diagrama, desactiva «Resumen del cambio» en la pestaña Ajustes de la consola.
El diagrama muestra el radio de impacto; si algo se rompe, eso lo dicen los hallazgos. El agente Blast Radius, uno de los 17 agentes especializados, busca llamadores rotos, superficies de API cambiadas y cambios de firma o de tipo de retorno que rompen otros archivos (cómo funciona, en un artículo aparte).
Preguntas frecuentes
¿Qué es el blast radius en software?
Es hasta dónde se extiende el efecto de un fallo o de un cambio. En infraestructura describe a cuántos usuarios llega una avería; en la revisión de código, qué archivos fuera del pull request llaman al código modificado o lo importan.
¿Blast radius y change impact analysis son lo mismo?
Son conceptos muy cercanos. Change impact analysis (análisis del impacto de un cambio) es el nombre general de la tarea de averiguar de antemano a qué más afectará un cambio. El blast radius de un pull request es el anillo más cercano de ese análisis: los archivos que usan directamente el archivo modificado.
¿Cómo encuentro quién llama a una función?
Usa «Find All References» en tu editor; el servidor de lenguaje resuelve todas las referencias del símbolo. Para echar un vistazo rápido basta con git grep -w nombre_funcion, pero tendrás que descartar a mano las coincidencias en comentarios y en otras definiciones con el mismo nombre. Para todos los archivos modificados de un pull request, en cambio, hace falta un recorrido que resuelva los imports al archivo modificado.
¿Funcionan los diagramas Mermaid en un comentario de pull request de GitHub?
Sí. GitHub dibuja diagramas Mermaid en issues, discusiones, pull requests, wikis y archivos Markdown. Basta con escribir la sintaxis en un bloque de código con la etiqueta de lenguaje mermaid.
¿Por qué no hay tests en el diagrama del radio de impacto?
Los tests están entre los archivos que más a menudo llaman al código modificado, y saturan el diagrama; en nuestro propio repositorio, la mayoría de las flechas de la primera versión venían de tests. Para quien abre el pull request, la pregunta de verdad es qué se ve afectado en el código de producción.
¿Qué significan las flechas discontinuas del diagrama?
Una flecha discontinua indica que el archivo llamador importa algo del archivo modificado, pero no se encontró ninguna llamada directa. Una flecha continua significa que se encontró al menos una llamada.
¿En qué lenguajes dibuja diffox el radio de impacto?
Python, JavaScript/TypeScript y Java. En estos lenguajes el import vincula un nombre y se puede averiguar a qué archivo apunta. En Go y en Ruby el import no vincula ningún nombre, así que diffox no dibuja flechas en esos lenguajes: en lugar de adivinar, deja la flecha fuera.