Arquitectura: qué funciona, y cómo verificarlo
Math Challenge se ejecuta enteramente sobre Cloudflare. Esta página separa lo que ya funciona de lo que solo está diseñado, y da el comando que verifica cada afirmación.
Lo que funciona hoy
math-challenge-web— Un Worker con Astro y Static Assets, que sirve los siete locales y las rutas que hay detrás.math-challenge-ingest— Un segundo Worker sin ninguna ruta pública. Solo se alcanza por service binding desde el primero.math-challenge-db— Una base de datos D1 en la región WNAM. La jurisdicción se fija al crear la base y después ya no se puede cambiar — una puerta que se cerró el día en que se creó, y que queda escrita en lugar de descubrirse más tarde.- Dos espacios de KV: los tokens de sesión de corta duración, y los indicadores de función con la caché del catálogo de contenido.
- Dos cubos de R2: los medios, y el archivo frío donde se escribirán las exportaciones de datos personales.
- Analytics Engine, con su binding declarado y reservado para la telemetría de intentos y el rendimiento de campo. Aún nadie le escribe: un conjunto de datos de Analytics Engine nace justo la primera vez que un Worker escribe en él.
Todo lo demás del inventario está diseñado y sin crear. Aparece más abajo, con su nombre, porque una página que solo enseña las piezas que existen es un folleto.
HTTP/3, QUIC y 0-RTT
HTTP/3 sobre QUIC está activo en la zona, y también la reanudación 0-RTT, que permite a un visitante que vuelve enviar la primera petición sin pagar un saludo nuevo. Ninguna de las dos se afirma a partir de una página de documentación: las dos líneas de abajo se leyeron directamente de producción, con la misma comprobación que se ejecuta después de cada despliegue. Un interruptor que alguien apaga en un panel no deja rastro en el repositorio: el código no se enteraría.
alt-svc: h3=":443"; ma=86400
TLS 1.3 · Max Early Data: 14336 Lo que esto no arregla: HTTP/3 acelera el transporte, no el trabajo. Un paquete pesado de JavaScript bloquea el hilo principal sobre QUIC exactamente igual que sobre TCP. Por eso el presupuesto de peso de más abajo importa más que el protocolo.
RPC nativo entre Workers
Los dos Workers se comunican mediante un service binding, con llamadas a métodos tipados en lugar de peticiones HTTP. Cloudflare describe lo que eso cuesta:
When you use Service Bindings, there is zero overhead or added latency. By default, both Workers run on the same thread of the same Cloudflare server.
RPC to another Worker (over a Service Binding) usually does not even cross a network. In fact, the other Worker usually runs in the very same thread as the caller, reducing latency to zero.
Un RPC que no cruza la red no puede ser superado por uno que sí, por eficiente que sea su serialización. El camino completo —primer Worker, segundo Worker, D1— responde en un endpoint público de estado, así que se puede verificar en lugar de creerse.
Por qué no gRPC
gRPC se pidió por su nombre. La investigación lo descartó por tres hechos independientes, cada uno suficiente por sí solo:
- Workers no puede hacer llamadas gRPC salientes. El runtime carece de streaming bidireccional de HTTP/2, y hay una incidencia abierta en el repositorio del propio runtime de Cloudflare que lo sigue.
- El navegador tampoco habla gRPC. El cliente web implementa un protocolo distinto, recurre a HTTP/1.1 —lo cual cancela algunas de las ventajas— y no admite ni streaming de cliente ni llamadas bidireccionales.
- Los trailers de HTTP, que gRPC necesita para transportar el estado, tienen soporte limitado en el proxy de borde de Cloudflare. Lo documentó la propia Cloudflare.
Lo que quedó no es un premio de consolación. Adoptar gRPC aquí habría sido adoptar la generación anterior con más trabajo y menos resultado. La petición y la evidencia que la revocó están ambas en el registro público de decisiones: para eso sirve tener uno.
Cero peticiones a terceros
Sin CDN de fuentes, sin script de analítica, sin marco incrustado, sin hoja de estilo externa. Ni una sola petición sale hacia un servidor que no sea nuestro. Esto se verifica contra el HTML que producción sirve realmente, no contra nuestras intenciones.
Raleway está autoalojada como fuente variable, en dos ficheros: latin y latin-ext. El segundo no es opcional: sin él, la ñ, la ç, la ã, la õ y la ü de cinco de nuestros locales recurren a otra tipografía, justo en los caracteres que los convierten en esos locales. Y la razón que pesa más que el rendimiento: cargar una fuente de un tercero le entrega a ese tercero la dirección y la firma del navegador de cada visitante, en las páginas públicas de un producto para niños.
La inferencia se ejecuta dentro de la red
Los 23 auditores adversariales ya se ejecutan sobre Workers AI, y el tutor va hacia allí también: la inferencia se queda en Cloudflare en lugar de irse a una API externa. La llamada ocurre dentro del Worker, sin viaje externo, y el dispositivo de referencia es un móvil Android de gama baja sobre datos móviles lentos, donde la latencia cuesta tanto como el precio.
Lo que eso cede queda escrito en vez de maquillado. El modo JSON de Workers AI es de mejor esfuerzo, así que la validación de esquema nos corresponde a nosotros. Un veredicto que no valida cuenta como auditor fallido, jamás como auditor limpio: el modo de fallo barato es volver a ejecutarlo, y el caro es una violación que nadie vio.
Los intentos no van a D1
D1 tiene un tope de 10 GB por base de datos. Una fila por intento llegaría a ese muro por error de diseño y no por crecimiento: el primer límite duro de esta arquitectura se alcanza equivocándose, no teniendo éxito. Los intentos en crudo van a Analytics Engine; D1 se queda con las cuentas, los metadatos de contenido y los agregados. Un auditor determinista bloquea el commit que lo olvide.
Medimos nosotros, y nunca a un niño
El rendimiento de campo lo medimos nosotros y nunca un tercero: un script en línea de unos 600 bytes que informa a un endpoint nuestro, que escribe en Analytics Engine — jamás en D1 y jamás en un servicio de fuera. Nada de lo que envía identifica a una persona, y no se carga nunca en la pantalla de un niño: el endpoint también rechaza esas franjas, de modo que los dos extremos fallan cerrados. Un auditor vigila el código; la comprobación de producción vigila la otra mitad, porque la plataforma puede inyectar una baliza propia a nivel de zona y eso no deja ningún fichero que mirar.
Lo que pesan las páginas
Página más pesada: 9,5 KB comprimidos con gzip, que es como viajan. Todo el JavaScript de cliente del sitio: 2,6 KB. Todo el CSS: 1,5 KB. El presupuesto que bloquea un commit es de 12 KB por página y 60 KB para todo el JavaScript de cliente junto.
El presupuesto de rendimiento, y lo que aún no afirmamos
El presupuesto es INP por debajo de 150 ms, LCP por debajo de 2,5 s y CLS por debajo de 0,1. 150 y no los 200 habituales, porque esto es un juego de alta frecuencia de interacción: un niño toca muchas veces por sesión y cada toque se mide. Es el perfil exacto donde INP se rompe.
Dicho sin adornos: eso son presupuestos, no resultados. Ninguna medición de campo lleva el tiempo suficiente para que el auditor que hace cumplir los umbrales tenga algo que hacer cumplir. Hasta entonces, esta página no afirma ningún resultado de rendimiento.
La flota de auditores
8 auditores deterministas se ejecutan en cada commit, en milisegundos, y lo bloquean. 23 auditores adversariales con modelos de lenguaje se ejecutan antes de abrir un PR, instruidos para encontrar la violación y no para aprobar. En total hay 39 previstos; 8 siguen esperando la fase que los habilita, y figuran como pendientes en vez de desaparecer en silencio.
Dos reglas los hacen servir en vez de estorbar. Cada auditor tiene que citar la decisión o el documento de investigación que hace cumplir: uno que no pueda señalar un identificador real está opinando, y su veredicto no bloquea. Y anular a un auditor exige escribir por qué, en un fichero que se commitea junto al cambio que necesitó la anulación.
Lo que aún no existe
El inventario se escribe antes de que los objetos existan, para que quien cree uno anote su línea en el registro en el mismo PR. Un recurso creado y no documentado es un recurso que nadie va a poder borrar dentro de un año. Esto está diseñado y sin crear:
- Durable Objects para ligas, aulas y el modelo adaptativo por niño — uno por liga y uno por aula, nunca uno global.
- Queues y Workflows para la corrección asíncrona y la generación de explicaciones.
- Un índice de Vectorize para recuperar sobre el banco de pistas curadas, acotado a contenido curado y nunca a vectores por niño.
- El propio banco de ítems, que es el producto y no un conjunto de datos.
Quién opera esto, y quién lo provee
Ignia opera la infraestructura. Cada objeto que esta página nombra vive en una cuenta de Cloudflare que gestiona Ignia — operar cuentas de Cloudflare, para sus propios productos y para sus clientes, forma parte de lo que hace Ignia. Math Challenge es un proyecto de Ignia, patrocinado por Ignia.
Cloudflare provee la plataforma. Workers, D1, KV, R2, Analytics Engine y la red sobre la que se ejecutan son productos de Cloudflare, operados por Cloudflare. Ignia opera; Cloudflare provee. Dos verbos, dos empresas, separados a propósito — y la razón de separarlos es la misma sobre la que se sostiene toda esta página: quien lee una página de arquitectura es quien verifica.
dig +short NS math.kilowatto.com
alberto.ns.cloudflare.com.
colette.ns.cloudflare.com. La otra mitad no se puede consultar en ninguna parte, y lo decimos. Que este dominio lo sirva Cloudflare cualquiera puede confirmarlo. Que Ignia opere la cuenta es una afirmación nuestra: no existe registro público donde ir a contrastarla. Decirlo así vale más que adornarlo, porque basta una sola afirmación que no se pueda verificar para que el lector deje de verificar las demás.
Lo que esta página no afirma, a propósito: que Ignia sea partner de Cloudflare. No citamos ningún nivel de partner ni mostramos ninguna insignia, porque no hay directorio público donde pudieras comprobarlo. En una página cuya promesa entera es «y así se verifica», una afirmación que no se puede verificar cuesta más de lo que vale.
Ignia, en sus propias palabras: ignia.cloud
Cómo verificar cualquiera de estas cosas
- el anuncio de HTTP/3 en las cabeceras de respuesta
curl -sI https://math.kilowatto.com/en/ | grep alt-svc- 0-RTT: el ticket de sesión de TLS 1.3 y su permiso de datos tempranos
openssl s_client -connect math.kilowatto.com:443 -tls1_3 -sess_out s.pem openssl sess_id -in s.pem -text | grep "Max Early Data"- el camino de RPC: primer Worker, segundo Worker, D1
curl -s https://math.kilowatto.com/api/health- los pesos citados arriba, desde el repositorio
node audits/bundle-budget.mjs
Fuentes
- About Service bindings — Cloudflare Workers docs
- We've added JavaScript-native RPC to Cloudflare Workers
- Support HTTP/2 bidirectional streaming (gRPC) in Workers/Durable Objects — cloudflare/workerd issue #6455
- gRPC Web (PROTOCOL-WEB) — gRPC core documentation
- Road to gRPC — Cloudflare blog
- HTTP/3 (with QUIC) — Cloudflare Speed docs
- D1 Platform limits — Cloudflare docs
- JSON Mode — Cloudflare Workers AI docs
Math Challenge es un proyecto de Ignia, y se ejecuta sobre Cloudflare. Son dos afirmaciones y se mantienen separadas a propósito: decir que Ignia provee el stack sería desmentible con una sola consulta de DNS, y el lector de una página de arquitectura es exactamente quien la haría. ignia.cloud