Durante la primera etapa de un proyecto estático, el modelo mental es cómodo: hay archivos fuente, un comando construye una carpeta de salida y el hosting la sirve. Ese modelo sigue siendo técnicamente cierto en Blupoli, pero dejó de ser suficiente para describir lo que significa publicar. El repositorio contiene más cosas que el producto público. Contiene juegos terminados y juegos en preparación, contenido editorial en distintos estados, compatibilidad con nombres antiguos, assets que necesitan normalización, rutas en varios idiomas y scripts que derivan información que no debería mantenerse a mano. Si el build se limitara a copiar, expondría decisiones internas como si fueran decisiones de producto.

Los cambios recientes nos obligaron a formalizar una idea que ya estaba apareciendo en varios lugares: existir en source no equivale a existir en producción. Entre ambos estados necesitamos una capa de publicación que interprete registros, aplique localización, genere rutas, normalice recursos, inserte observabilidad y, finalmente, rechace una salida que contradiga los contratos públicos. Esta entrada no trata de por qué preferimos calidad a cantidad —eso lo contamos en Calidad antes que cantidad—, sino de la maquinaria que hace posible aplicar esa decisión sin depender de recordar manualmente qué debe salir y qué no.

El build dejó de ser una fotocopiadora

La diferencia puede explicarse con un caso sencillo. Supongamos que añadimos un juego al catálogo porque queremos trabajar en él. Necesitamos nombre, categoría, metadatos y quizá una tarjeta visible para comunicar que llegará más adelante. Pero no queremos una ruta jugable pública, no queremos que el botón aleatorio lo seleccione, no queremos que el sitemap lo anuncie como disponible y no queremos que los contadores de juegos terminados aumenten. Si la presencia de un directorio fuese suficiente para publicar, cada uno de esos comportamientos tendría que corregirse después con excepciones.

El registro de release invierte la relación. Un juego nuevo nace como coming-soon. El catálogo puede conocerlo, pero las superficies públicas derivan su comportamiento del estado. Cuando el juego supera su proceso de finalización, el estado cambia y el mismo pipeline puede generar rutas, enlaces y estadísticas coherentes. La fuente de verdad deja de ser «hay archivos» y pasa a ser «el registro declara que esta experiencia está disponible». Esa distinción es pequeña en JSON y enorme en producto.

Pipeline de publicación

El repositorio contiene posibilidades; el build decide qué combinación cumple el contrato público.

FuentesApps, juegos, editorial, traducciones y assets.
RegistrosEstado de release, agrupación editorial y locales.
TransformaciónRutas, normalización, SEO, observabilidad y recursos.
GatesInvariantes que deben cumplirse antes de desplegar.
DistSolo la representación pública validada.

Un estado de release debe afectar a todo, no solo al botón

Marcar una tarjeta como «Próximamente» es la parte visible del sistema, pero sería insuficiente si detrás siguiera existiendo una ruta indexable. Por eso el estado se aplica en varias capas. Los juegos futuros aparecen como tarjetas no navegables, con tratamiento visual diferenciado. No se generan sus rutas públicas de juego. Se excluyen de sitemap y de enlaces que prometen jugar. El selector aleatorio no debe enviarte a una experiencia no publicada. Los contadores globales, por modo y por categoría distinguen entre anunciado y jugable en lugar de inflar el número disponible.

La corrección posterior que permitió mostrar próximos juegos sin contarlos como disponibles es importante porque demuestra que incluso un buen modelo de estado puede fallar si una superficie interpreta mal el dato. No basta con tener available y coming-soon; cada consumidor debe saber qué pregunta está respondiendo. «¿Cuántos juegos conoce el catálogo?» y «¿cuántos puedo jugar ahora?» son métricas distintas. El pipeline genera información derivada precisamente para que las páginas no vuelvan a inventar su propia definición.

De ahí nace también catalog-stats.json. En lugar de mantener una cifra fija en múltiples textos, el build calcula el estado real del catálogo. Esto elimina un tipo de deuda que ya habíamos sufrido: afirmaciones públicas que envejecen en cuanto cambia el inventario. El número de juegos deja de ser una constante editorial y se convierte en un resultado. Más importante todavía, ese resultado puede usar la definición correcta de «publicado».

English-first cambió la entrada del pipeline

La publicación multilingüe añadió una dificultad distinta. Blupoli había crecido con mucho contenido y decisiones nacidas en español, mientras el producto ya servía varios idiomas. Convertir inglés en la experiencia pública por defecto no podía reducirse a traducir la home. Había que decidir qué significa la raíz, cómo se construyen las variantes localizadas, cómo se comporta el selector compartido y qué ocurre cuando una pieza editorial todavía no tiene una versión equivalente.

El trabajo reciente estableció inglés como idioma real por defecto en la web principal y añadió versiones localizadas para español, italiano, portugués, francés y alemán. En Puzzles, el runtime de los juegos también necesita entregar UI inglesa real. La dificultad está en que «default» no significa necesariamente «misma ruta» en todos los productos. La capa de publicación debe conocer las convenciones de cada aplicación y producir enlaces coherentes sin duplicar contenido ni crear rutas que compitan en SEO.

El fallback editorial ilustra el equilibrio. Si un índice inglés todavía no dispone de una tarjeta traducida, el sistema puede necesitar recurrir temporalmente a la fuente española en lugar de dejar un hueco o romper la página. Eso no convierte el español en default de la plataforma; representa una estrategia de degradación explícita mientras la cobertura editorial avanza. Lo importante es que la decisión ocurra en una capa conocida y verificable, no como una consecuencia accidental del orden de archivos.

Localizar también significa localizar metadatos

Una página que muestra inglés pero conserva título, descripción o datos estructurados en español no está realmente localizada. Lo mismo ocurre con enlaces canónicos, hreflang, Open Graph y tarjetas sociales. La arquitectura editorial reciente ya obligaba a tratar SEO como parte del contenido; el movimiento English-first hizo más evidente que el pipeline debe revisar cada idioma como una publicación completa.

Por eso la localización y el SEO están conectados al build en lugar de ser una fase manual posterior. Las variantes necesitan títulos naturales, no sustituciones palabra por palabra. Los identificadores técnicos permanecen estables, mientras el texto visible cambia. Las rutas deben apuntar a equivalentes reales. Y si una página se publica en seis idiomas, las comprobaciones deben recorrer las seis representaciones. Un fallo en la quinta variante sigue siendo un fallo de producción aunque la raíz inglesa funcione.

La observabilidad tuvo que entrar antes del deploy

Otro límite del modelo «copiar y servir» es que no explica qué ocurre después. Una web estática puede fallar en el navegador aunque el hosting entregue todos los archivos: una excepción JavaScript, un rechazo de promesa, un flujo de navegación que no se ejecuta como esperábamos. Sin una capa mínima de observabilidad, esos fallos solo existen para la persona que los encuentra.

La integración reciente añadió Firebase Analytics a la web principal y Puzzles mediante la configuración del Hosting, junto con consentimiento compartido entre dominio y subdominios. El banner se adapta a los seis idiomas públicos. Además, window.error y unhandledrejection se registran como eventos de excepción, y una API pequeña, window.BlupoliObservability.logEvent(...), permite instrumentar eventos propios sin acoplar cada módulo directamente a detalles de inicialización.

Es importante describir el alcance con precisión. Esto no equivale a tener Crashlytics en navegador ni a un sistema completo de error reporting con trazas avanzadas. Para ese nivel necesitaríamos otra solución, como una integración dedicada de reporting. Lo que sí tenemos es una capa común que convierte ciertos fallos antes silenciosos en señales y que puede insertarse de manera consistente en el HTML generado. La publicación ya no termina cuando el archivo llega al CDN; incluye la capacidad básica de observar cómo se comporta después.

Consentimiento compartido, otra vez una frontera de plataforma

Analytics introdujo el mismo problema de fronteras que tema e idioma: Blupoli no debería pedir una decisión de consentimiento independiente cada vez que el usuario cruza a un subdominio. La solución necesitaba un estado compartido y un banner que pudiera representarse correctamente en cada locale. La infraestructura de observabilidad no podía diseñarse solo desde el punto de vista de «enviar eventos»; debía incluir cómo y cuándo estamos autorizados a hacerlo.

Esto también influye en el build. La instrumentación se inyecta en las salidas correspondientes y la política CSP debe permitir los endpoints necesarios. Si una página queda fuera de la inyección o una política de seguridad bloquea el transporte, la observabilidad existe en el repositorio pero no en el producto. De nuevo aparece la misma idea: el pipeline no transporta archivos pasivamente; compone un contrato operativo.

Las portadas editoriales revelaron un segundo tipo de estado

Mientras el registro de juegos separa «implementado» de «publicado», el sistema editorial necesitaba separar «asset presente» de «asset canónico». Durante la evolución de Blog y Devlog coexistieron referencias antiguas a portadas bajo rutas de cada artículo y el nuevo esquema de assets editoriales. Esa convivencia produjo un riesgo muy concreto: una página podía heredar una portada, insertar otra y terminar con duplicados, o apuntar en Open Graph a un recurso distinto del que mostraba el artículo.

Las correcciones recientes atacaron el problema en dos pasos. Primero, el build preservó correctamente las imágenes fuente necesarias, eliminó portadas heredadas duplicadas y migró referencias antiguas hacia los assets editoriales canónicos. Después, una normalización específica pasó a ejecutarse en un punto estable del pipeline: después de construir la arquitectura editorial y antes del quality gate. Esa fase elimina restos de img o figure de portada heredada, inserta exactamente una portada canónica y actualiza og:image, twitter:image y la imagen del JSON-LD para que todos describan el mismo recurso.

Una sola verdad pública

El mismo principio gobierna juegos y artículos: una fuente puede existir sin que todas sus representaciones sean publicables.

Juego en sourcePuede estar anunciado pero todavía no disponible.
Release registryDecide rutas, enlaces y conteo público.
Artículo en sourcePuede contener referencias heredadas o assets parciales.
Normalización editorialDecide portada, metadata y estructura canónica.

Por qué «exactamente una portada» merece un gate

Podría parecer excesivo fallar un build porque una página contiene dos portadas. Sin embargo, una duplicación editorial no es solo estética. Puede afectar al layout, al rendimiento, a lectores de pantalla, a previews sociales y a la percepción de calidad. Y, sobre todo, es una condición que una máquina puede verificar sin ambigüedad. Si el contrato dice una portada canónica por artículo, aceptar cero o dos significa convertir una regla precisa en una sugerencia.

El gate actual revisa las variantes de idioma y falla si persisten rutas heredadas de portada o si el número de portadas no es el esperado. También se añadió validación para imágenes locales que no existen. Este tipo de comprobación tiene una rentabilidad alta: un enlace roto puede esconderse en un artículo que nadie abre durante la revisión, mientras el build puede recorrer sistemáticamente todos los documentos.

Normalizar después de generar, validar después de normalizar

El orden de las fases resultó tan importante como las fases mismas. Si validamos demasiado pronto, podemos rechazar una fuente que el pipeline está diseñado para normalizar. Si normalizamos después del quality gate, el gate está revisando una representación distinta de la que finalmente publicamos. Por eso la portada canónica se consolida después de la arquitectura editorial y antes de la validación final. El gate observa la salida que realmente queremos desplegar.

Esta idea se aplica más allá de las portadas. La localización debe ocurrir antes de comprobar cobertura de idioma. La generación de rutas debe incorporar el estado de release antes de buscar enlaces a juegos futuros. La instrumentación debe estar presente antes de revisar CSP. Un pipeline fiable no es una lista de scripts; es una secuencia donde cada etapa puede asumir contratos producidos por la anterior.

Los gates no deberían conocer intenciones vagas

Otra lección ha sido formular invariantes concretas. «La web debe estar bien localizada» es demasiado amplio para un test. «No debe quedar un selector heredado», «cada artículo tiene una portada canónica», «un juego coming-soon no tiene ruta pública», «no hay enlaces públicos a experiencias futuras» o «no quedan afirmaciones fijas sobre un número antiguo de juegos» son condiciones mucho más útiles. Un gate funciona cuando puede decir qué contrato se rompió.

Eso no elimina la revisión humana. Un artículo puede tener portada única y ser visualmente mediocre. Una traducción puede contener todas las claves y sonar artificial. Un juego puede estar correctamente marcado como disponible y tener una interacción confusa. Automatizamos invariantes para que la revisión humana no tenga que gastar tiempo en contar etiquetas o perseguir archivos inexistentes. La calidad editorial y de producto sigue necesitando lectura, juego y criterio.

El pipeline también protege la historia del proyecto

La transición de Blupoli a Blupoli dejó nombres antiguos en archivos y rutas internas que todavía cumplen una función de compatibilidad. El build ha ido normalizando la identidad pública sin exigir una purga destructiva de todo identificador histórico. Esto es importante porque migrar no significa fingir que el pasado nunca existió. Las referencias históricas pueden seguir siendo correctas en artículos que cuentan esa etapa, mientras los títulos, navegación y producto actual utilizan Blupoli.

La misma estrategia reduce riesgo técnico. Renombrar cada archivo interno en una sola operación puede romper scripts que no aportan ninguna mejora visible. En cambio, establecer contratos nuevos para lo que se publica y añadir gates contra branding obsoleto en superficies actuales permite avanzar de forma incremental. El pipeline actúa como frontera: tolera compatibilidad interna donde es necesaria y evita que esa compatibilidad vuelva a definir la identidad pública.

Qué gana el desarrollo diario

La consecuencia práctica es que añadir trabajo al repositorio se vuelve menos peligroso. Podemos registrar un juego antes de terminarlo sin publicarlo accidentalmente. Podemos mantener fuentes editoriales y dejar que una fase canónica resuelva la portada. Podemos añadir un nuevo locale sabiendo que las comprobaciones recorrerán su salida. Podemos cambiar un asset compartido y detectar referencias antiguas. La infraestructura no sustituye el cuidado, pero hace que el estado intermedio sea una condición esperada en lugar de una amenaza.

También cambia la forma de depurar. Si una cifra es incorrecta, podemos preguntar qué registro y qué derivación la produjeron. Si una portada se duplica, existe una fase concreta responsable de normalizarla. Si un juego futuro tiene enlace, el gate debería señalar la violación. Si una excepción ocurre en navegador, tenemos al menos una señal básica de observabilidad. La arquitectura crea lugares donde buscar, y esa propiedad se vuelve cada vez más importante a medida que el repositorio crece.

Qué gana la experiencia pública

Para el visitante, el resultado es menos espectacular pero más importante. Los contadores describen lo que realmente se puede jugar. Los próximos juegos pueden descubrirse sin convertirse en callejones sin salida. El idioma de entrada es coherente. Las portadas editoriales no aparecen duplicadas y los previews sociales apuntan al mismo recurso que la página. El consentimiento no se reinicia arbitrariamente al cruzar una frontera de producto. Y algunos errores de navegador dejan una señal que podemos investigar.

Todo esto comparte una característica: son problemas de consistencia. Ninguno añade una mecánica de puzzle. Ninguno produce por sí mismo una gran captura para una nota de lanzamiento. Pero juntos determinan si Blupoli se comporta como un conjunto de archivos o como un producto que entiende su propio estado.

Qué queda pendiente

El pipeline todavía puede mejorar. La observabilidad web es deliberadamente básica y no sustituye un sistema especializado de seguimiento de errores. Las pruebas de extremo a extremo pueden cubrir mejor transiciones entre dominios, locales y estados persistidos. La publicación editorial puede seguir reduciendo compatibilidad heredada cuando deje de ser necesaria. Y cada nuevo producto dentro del monorepo pondrá a prueba si los contratos actuales son realmente de plataforma o estaban demasiado adaptados a Puzzles.

También debemos vigilar el coste de los gates. Una validación útil debe ser suficientemente rápida y explicar bien el fallo. Si cada regla añade minutos o produce mensajes opacos, los desarrolladores empiezan a verla como fricción y no como protección. La evolución natural será mantener las invariantes baratas cerca del build y reservar pruebas más costosas para los puntos donde aporten evidencia real.

La lección: publicar es interpretar estado

La idea que resume esta etapa es sencilla: un sistema de publicación moderno, incluso si termina en HTML estático, no es una operación de copia. Es un intérprete del estado del proyecto. Lee qué juegos están listos, qué idiomas existen, qué contenido pertenece a cada sección, qué assets son canónicos, qué compatibilidad debe conservarse y qué condiciones hacen que una salida sea inválida. Después produce una representación pública que debería ser más estricta y coherente que el árbol de fuentes del que procede.

Esto conecta con nuestro trabajo anterior de i18n y gates de calidad y con la arquitectura que separó Blog y Devlog, pero el sistema reciente va un paso más allá: esas ideas ya no están aisladas por área. Release de juegos, localización, editorial, assets y observabilidad convergen en la misma frontera de publicación.

La ventaja no es que el build se haya vuelto más sofisticado por sí mismo. La ventaja es poder expresar decisiones de producto como contratos ejecutables. «Próximamente no significa jugable». «Inglés por defecto no significa metadatos españoles». «Una portada canónica significa una». «Una preferencia compartida no debe reiniciarse al cambiar de superficie». Cuando esas frases viven solo en documentación, dependen de memoria. Cuando una parte razonable vive en el pipeline, el sistema ayuda a recordarlas.

Eso nos permite seguir creciendo sin exigir que cada cambio conozca toda la historia de Blupoli. El repositorio puede contener experimentos, migraciones y trabajo incompleto. La salida pública no tiene por qué reflejar esa complejidad. Entre ambas cosas existe ahora una frontera más consciente: un pipeline que no pregunta únicamente «¿puedo generar esta página?», sino «¿esta página representa correctamente el estado que queremos publicar?». Esa segunda pregunta es la que convierte un build en infraestructura de producto.