Versionado
Un solo número, y es una versión mayor: qué se publica sin tocarlo, qué obliga a subirlo y por qué el formato no tiene versión menor a propósito.
Esta página responde a una pregunta: ¿qué pasa cuando el juego es más viejo que
el contenido que le están entregando? Ese es el caso normal, no el caso límite:
una pantalla
hot-updateada hoy a los
jugadores aterriza en la build que se instalaron hace meses. Un solo número
decide si los dos pueden trabajar juntos siquiera, y es la v del
envelope. Si el SDK
implementa esa mayor, renderiza el payload e ignora en silencio lo que sea más
nuevo y no reconozca. Si no la implementa, rechaza el payload entero antes que
dibujarlo mal.
Enviar UI a un juego que ya está en manos de los jugadores es para lo que
existe este formato, y hay tres páginas que se lo reparten. Esta página
dice si un SDK y un payload pueden siquiera encontrarse.
Loading dice qué hace el SDK con el payload una
vez se encuentran: qué repara, qué rechaza y qué le cuenta al juego.
El canal del host es la llamada que entrega
el payload nuevo, reload, y el callback por el que vuelven los diagnósticos.
Un envelope lleva un único número de versión:
{ "v": 1, "tokens": {}, "views": {} }
v es la versión mayor, y es el único número de versión del formato. Un SDK
implementa exactamente una mayor y rechaza cualquier otra.
Esto importa más aquí que en una librería, porque las dos partes se mueven por separado.
La política
Todo cambio del formato es de uno de dos tipos, y cuál sea decide si los juegos que ya están ahí fuera siguen funcionando. No hay un tercer caso:
normativePolítica de versiones
| Cambio | v | Qué hace un SDK más viejo |
|---|---|---|
| Aditivo — el formato crece | sin tocar | Ignora lo que no conoce y renderiza el resto. |
| Rompedor — el formato cambia de opinión | sube | Rechaza el payload (unsupported-version, fatal). |
No hay versión menor, y es deliberado. Un número menor solo podría decirle a un SDK «este contenido usa cosas que puede que no conozcas», y la respuesta a eso ya está escrita dentro del formato: las ignora, con reglas que son normativas y están probadas. Lo que un SDK necesita decidir de verdad es binario —¿puedo renderizar esto o no?— y eso es exactamente lo que responde la mayor. Cada cargador se queda con una comparación en vez de dos, y no hay una segunda regla de compatibilidad que mantener coherente entre targets.
El coste es real y está aceptado: un SDK v1 no puede reportar «este contenido se construyó para una v1 posterior». Renderiza lo que entiende y se calla sobre el resto, que es lo mismo que hace con una prop que sencillamente no venía.
Qué es aditivo
Estos cambios se publican sin tocar v, porque la
tolerancia hacia adelante
ya define qué hace con ellos un SDK más viejo:
- Un tipo de nodo nuevo. Un SDK que no lo conoce lo renderiza como un
Containerconservandolayout,style,visible,disabledychildren. - Una propiedad opcional nueva, en un nodo o dentro de
Style/Layout. Las propiedades desconocidas se ignoran en silencio, y ausente significa «el valor por defecto», que es lo que aplica el SDK más viejo. - Un valor nuevo en un conjunto cerrado (
Easing,ImageFit,AnchorAt,GroupBehavior,ScrollAxis,StateName,OverlayTrigger). El validador comprueba formas, nunca vocabularios, y un valor desconocido cae al valor por defecto de la propiedad. - Un comportamiento de grupo nuevo. Se ignora, así que los hijos se maquetan como hermanos ordinarios.
- Un token nuevo en el diccionario, un campo nuevo en una entrada de asset, un código de diagnóstico nuevo.
Una capacidad nueva es aditiva solo si su ausencia es una imagen razonable de
la UI, solo si su
degradación se sigue
leyendo como la pantalla que quería ser. Un Repeat degrada a una copia
estática de su plantilla, un ProgressBar a su pista con un relleno sin
dimensionar, un Spinner a sus cuentas en reposo. Si un tipo de nodo nuevo
degradara a algo que engaña —un control con pinta de operable que no lo es, un
diálogo que se renderiza como una caja opaca encima de la pantalla— no es
aditivo, sea cual sea su forma.
Emitir una capacidad aditiva es por tanto una decisión de autoría: el contenido sigue cargando en todas partes, y se ve completo solo allí donde el SDK es lo bastante nuevo.
Qué rompe
Un cambio pertenece aquí cuando un SDK más viejo renderizaría algo mal en vez de algo incompleto. Esa es la prueba entera: el silencio es aceptable, una mentira no.
normativeEstos exigen una mayor nueva, porque ninguna regla de tolerancia hacia adelante puede absorberlos:
- Quitar o renombrar un tipo de nodo, una propiedad o un valor de un conjunto cerrado.
- Cambiar el significado o el valor por defecto de una propiedad existente. Un SDK viejo sigue aplicando el significado viejo al mismo JSON, en silencio.
- Cambiar el contrato de un slot posicional: qué hijo es la cabecera de un
Collapse, el indicador de marcado de unToggle, el pulgar de unSlider, la plantilla de unRepeat. Los slots se leen por índice, así que una renumeración es invisible y total. - Cambiar la salida de un algoritmo normativo: el orden de mezcla de estados, el algoritmo de partido de líneas, las curvas de easing, la puntuación de navegación espacial, la resolución de rutas dentro de ámbitos de elemento. Dos SDK sobre la misma mayor tienen que producir el mismo frame.
- Hacer obligatoria una propiedad opcional, o cambiar la forma del propio envelope.
- Convertir una degradación silenciosa en un rechazo, o al revés.
Arreglar un fallo —donde una implementación no coincidía con esta especificación— no es un cambio rompedor. La especificación es el contrato; una implementación que no encajaba con ella ya estaba equivocada.
Qué hacen los SDK
supportsVersion(v) ⟺ v is an integer and v === IR_VERSION
IR_VERSION es la mayor que implementa un SDK: hoy, 1. Un desajuste, en
cualquiera de las dos direcciones, es fatal, se reporta como
unsupported-version y el payload no llega nunca a ser una view. El contenido
más viejo que el SDK se rechaza por la misma razón que el más nuevo: un SDK v1
no lleva la semántica de v2, y un SDK v2 no se queda con la de v1.
Rechazar no es reventar. En un hot-update es una actualización descartada: la UI que ya está en pantalla se queda exactamente como está. Solo un primer montaje de un payload no soportado aflora como error hacia el juego, porque no hay nada en pantalla que proteger.
Las versiones de los paquetes son otro número
Los paquetes de npm (@zabloo/format, @zabloo/react) y los SDK de cada motor
siguen semver corriente, y sus versiones no son la versión de la IR. La
mayor de un paquete puede cambiar por razones que no tienen nada que ver con el
formato —un export renombrado, una versión de Node que se deja de soportar—
mientras la IR que lee y escribe se queda en v: 1.
El único número que decide si un payload y un SDK pueden encontrarse es la v
del envelope.