En el post anterior sobre MeteoTrail me centré en el porqué: los directores de carrera no necesitan una previsión regional, necesitan saber qué va a pasar en el kilómetro 43, a 2.400 metros, dentro de cuatro horas, porque ahí es donde van a estar sus corredores. Este post va del cómo: el problema de ingeniería real que hay detrás de convertir lo que está pasando exactamente en ese punto de la montaña en algo en lo que un director de carrera pueda confiar lo suficiente como para actuar. Parte de lo que sigue son decisiones que tomamos de forma deliberada; otra parte se acerca más a "esta es la arquitectura que necesita un sistema así", razonada a partir de las restricciones más que un relato línea a línea de cada detalle interno.
1. Muchas fuentes, un solo checkpoint
Un checkpoint en una ultra de montaña no es una ubicación única y estable como lo es una ciudad. Es un punto de la ruta que la organización define con meses de antelación, que a veces cae justo sobre una frontera nacional —las carreras por el Valle de Arán cruzan a Francia, y a veces a Andorra, dentro de la misma etapa—, y que hay que resolver, en tiempo real, contra la fuente meteorológica oficial que realmente cubre ese trozo de terreno.
Para cada checkpoint hay que averiguar, antes de la carrera, en qué zona de aviso de qué agencia cae, qué webcams públicas de la ruta están lo bastante cerca y bien orientadas hacia ese punto, si hay una estación meteorológica privada o semioficial cercana con mejor resolución que la oficial más próxima, y de dónde hay que muestrear los datos de detección de rayos para ese radio exacto. Eso son cuatro o cinco sistemas ascendentes distintos, cada uno con su propia forma de API, su propio intervalo de actualización y su propio modo de fallo.
- APIs oficiales de agencias meteorológicas (condiciones actuales, previsiones a 48 horas y 7 días, avisos) — por ejemplo AEMET, Météo-France, IPMA, Aeronautica Militare
- Feeds de webcams públicas a lo largo de la ruta
- Detección de rayos en tiempo real
- Estaciones meteorológicas privadas o semioficiales cerca del checkpoint
El checkpoint, dicho de otro modo, no es el dato en bruto en sí mismo: es la vista reconciliada que construimos alrededor de un punto geolocalizado, obtenida de la combinación de feeds que realmente estén disponibles y sean fiables en ese momento. La previsión a 48 horas que ve un director de carrera para un checkpoint concreto ya es el resultado de elegir, por tipo de dato, la fuente en la que confiamos más en ese momento para esa ubicación concreta — no un único feed reenviado sin tocar.
2. Decidir qué es lo bastante importante como para avisar
Agregar datos es solo la mitad del problema. La mitad difícil es decidir cuándo un cambio merece despertar a alguien. Un director de carrera no quiere un email cada vez que la lectura de viento se mueve medio kilómetro por hora, pero sí quiere absolutamente uno en cuestión de minutos si se emite un aviso oficial de tormenta para un checkpoint al que sus corredores llegarán dentro de tres horas.
La forma aproximada de la solución es un motor de reglas por umbrales que se ejecuta en cada actualización relevante por checkpoint, no solo con un temporizador: cruzar un umbral de viento o temperatura, un aviso oficial nuevo que aparece donde antes no había ninguno, rayos detectados dentro de un radio alrededor del checkpoint, o una caída brusca de temperatura en una ventana corta. Algo así, muy simplificado respecto a lo que necesitaría un conjunto de reglas real:
def evaluate_checkpoint(checkpoint, previous_state, current_reading):
triggers = []
if crosses_threshold(previous_state.wind_kmh, current_reading.wind_kmh, threshold=60):
triggers.append(Alert("wind", severity="high"))
if current_reading.has_new_agency_alert and not previous_state.has_agency_alert:
triggers.append(Alert("agency_alert", severity=current_reading.alert_level))
if current_reading.lightning_strikes_last_10min(radius_km=15) > 0:
triggers.append(Alert("lightning", severity="critical"))
if current_reading.temperature_drop_c(last_hours=3) > 8:
triggers.append(Alert("temp_drop", severity="medium"))
if not triggers:
return None
return build_notification(checkpoint, triggers, previous_state)
Lo genuinamente difícil no es escribir reglas como estas, sino ajustar la severidad y el radio para que el sistema escale la tormenta que se dirige hacia el kilómetro 40 sin mandar también un email a cada organizador cada vez que una webcam falla o una estación da una lectura ruidosa. Ese ajuste tiene que tener en cuenta que una sola carrera puede tener checkpoints bajo la jurisdicción de tres países a la vez, cada agencia con un vocabulario de avisos y una escala de severidad distintos.
3. Dejar que una persona anule la automatización
Nada de esto sustituye el criterio humano. El backoffice de MeteoTrail permite que un meteorólogo contratado vea todo lo que el pipeline automático está viendo para una carrera y publique un informe manual que se envía a toda la organización, anulando lo que muestra el feed automático para ese checkpoint.
El problema de diseño interesante es qué pasa justo después de publicar ese informe: el pipeline automático no se detiene. Así que el sistema necesita una regla de precedencia clara y visible: un informe humano tiene que prevalecer sobre la vista automática para ese checkpoint mientras deba seguir siendo la palabra autorizada, sin desaparecer en silencio en cuanto llega la siguiente actualización automática, y sin que ambos se muestren nunca lado a lado como si tuvieran el mismo peso. En la práctica eso significa que un informe necesita un alcance explícito, una procedencia clara y una regla de caducidad o de sustitución, para que un informe manual desactualizado de hace seis horas no bloquee para siempre una lectura automática nueva y materialmente distinta.
4. Lo que todavía es difícil
Algunas cosas de este problema todavía no tienen una respuesta limpia. Las fuentes discrepan entre sí más de lo que gustaría, y elegir un ganador por tipo de dato y por checkpoint sigue siendo en parte heurístico. Los checkpoints fronterizos son su propia categoría de dolor de cabeza — una etapa que empieza bajo la zona de aviso de una agencia y termina bajo la de otra necesita ambas. La fiabilidad de las webcams está completamente fuera de nuestro control. Y un solo meteorólogo cubriendo varias carreras simultáneas durante un fin de semana de verano muy cargado tiene que priorizar, lo que significa que la capa de anulación manual tiene que ser genuinamente opcional y la automatización tiene que ser lo bastante buena como para sostenerse sola la mayor parte del tiempo.
Nada de esto es trabajo exótico de sistemas distribuidos, y no hace falta que lo sea. Pero sí es un problema de integración real disfrazado de app del tiempo. Si el post de marzo iba de por qué los directores de carrera necesitaban esto, este va de lo que hace falta, por debajo, para que "qué tiempo hace ahora mismo en el checkpoint 7" sea una pregunta con una respuesta fiable.
