wandres.dev
SCXML Y EL ESTÁNDAR · la especificación

Qué es SCXML: el estándar que casi nadie escribe

SCXML es la Recomendación del W3C que fija, en prosa normativa y en pseudocódigo ejecutable, qué significa exactamente un statechart. Nació en 2005 dentro del grupo de navegadores de voz, alcanzó el estatus de Recomendación en 2015, y tomó de Harel la notación y de UML el vocabulario para producir algo que ninguno de los dos tenía: un algoritmo de interpretación tan preciso que dos implementaciones independientes producen la misma traza ante el mismo evento. Esta lección reconstruye esa genealogía, disecciona la anatomía de un documento SCXML y explica por qué XState, que casi nunca ve un byte de XML, se define a sí mismo por conformidad con él.

⏱ 20 min

Llevas nueve niveles escribiendo máquinas sin preguntar de dónde salen sus reglas. Por qué el hijo gana al padre cuando ambos podrían transicionar. Por qué un evento levantado con raise se procesa antes que uno enviado desde fuera. Por qué al entrar en un estado compuesto se ejecuta primero el entry del padre y luego el del hijo, y no al revés. Ninguna de esas decisiones es arbitraria ni es una invención de XState: están escritas, palabra por palabra, en una Recomendación del W3C de 2015 llamada SCXML. La paradoja de este estándar es que su formato —XML— casi nadie lo usa, mientras que su contenido —un algoritmo de interpretación de treinta páginas— lo obedece medio ecosistema sin saberlo. Este nivel entero trata de esa parte invisible: no del XML, sino de la semántica que el XML solo sirve para transportar.

🎯 Al terminar esta lección sabrás
  • Situar SCXML en la genealogía que va de Harel a UML y de ahí a la W3C.
  • Leer la anatomía de un documento SCXML y reconocer cada elemento en XState.
  • Separar la capa sintáctica —el XML— de la capa normativa —el algoritmo—.
  • Entender por qué XState declara conformidad con SCXML sin procesar XML.

De Harel a la Recomendación: tres décadas de precisión creciente

David Harel publicó en 1987 el artículo que fundó el campo, Statecharts: A Visual Formalism for Complex Systems, escrito a partir de su trabajo sobre la aviónica de un caza donde las máquinas de estado planas habían colapsado bajo la explosión combinatoria. Aquel artículo aportó la jerarquía, la ortogonalidad y la historia —las tres ideas del nivel 2—, pero era ante todo un formalismo visual: definía qué se dibuja, no exactamente qué ocurre al ejecutarlo. La semántica operacional llegó después, con STATEMATE y el artículo de Harel y Naamad de 1996, y llegó ya bifurcada.

Esa bifurcación es el problema central de la historia. En 1994 Michael von der Beeck catalogó más de veinte variantes de statecharts que diferían en cuestiones nada cosméticas: si el efecto de una transición es visible en el mismo paso o en el siguiente, si gana la transición más externa o la más interna, si un evento generado internamente se consume ya o espera al próximo ciclo. Dos herramientas podían aceptar el mismo diagrama y ejecutarlo distinto. Cuando UML absorbió los statecharts a finales de los noventa les dio un vocabulario común y una notación estable, pero su especificación describía la semántica en prosa deliberadamente abierta, con puntos de variación explícitos que cada fabricante rellenaba a su gusto.

Conviene medir bien la gravedad de aquello. No se trataba de que las herramientas tuvieran atajos distintos o exportaran formatos incompatibles, problemas irritantes pero superficiales. Se trataba de que el mismo dibujo, con las mismas cajas y las mismas flechas, describía comportamientos diferentes según quién lo ejecutara, y de que no había forma de decidir cuál era el correcto porque no existía una definición de correcto. Un diagrama de estados era, en la práctica, documentación con apariencia de especificación: precisa a la vista, ambigua en el fondo, y por tanto inútil como contrato entre un equipo que diseña y otro que implementa.

flowchart LR
H[Harel 1987 formalismo visual] --> S[STATEMATE 1996 semantica operacional]
H --> V[Variantes academicas e industriales]
S --> U[UML State Machines]
V --> U
U --> W[W3C SCXML 2005 a 2015]
W --> X[XState SCION Qt SCXML Commons SCXML]
style H fill:#cba6f7,color:#11111b
style W fill:#a6e3a1,color:#11111b
style X fill:#89b4fa,color:#11111b

SCXML nació en 2005 en un lugar inesperado: el grupo de trabajo de navegadores de voz del W3C, que necesitaba una capa de control por encima de VoiceXML y CCXML para orquestar llamadas telefónicas. El nombre completo lo delata: State Chart XML: State Machine Notation for Control Abstraction. Diez años de borradores después, el 1 de septiembre de 2015, se convirtió en Recomendación. Y en ese trayecto ocurrió lo decisivo: el grupo entendió que una notación sin algoritmo no resuelve nada, y añadió un apéndice normativo con el intérprete completo escrito en pseudocódigo. Ese apéndice, no la sintaxis, es lo que convirtió a SCXML en el árbitro del dominio.

El origen telefónico dejó dos huellas visibles en el diseño. La primera es la obsesión por la comunicación entre sesiones: SCXML no asume que una máquina viva sola, sino que define procesadores de entrada y salida de eventos —uno interno, uno sobre HTTP, uno sobre el DOM— porque su caso de uso original era coordinar máquinas distribuidas en una centralita. La segunda es la neutralidad respecto al lenguaje de expresiones: la Recomendación admite tres modelos de datos —null, ecmascript y xpath— y deja la puerta abierta a otros, precisamente para no atar el control a ninguna plataforma. Ambas decisiones envejecieron de forma desigual, pero explican por qué el vocabulario incluye cosas que a un desarrollador de interfaces le parecen exóticas.

📝
El apendice D es el documento importante

La Recomendación tiene seis capítulos de prosa normativa sobre elementos y atributos, y un apéndice titulado Algorithm for SCXML Interpretation que contiene el intérprete entero en un pseudocódigo con tipos, procedimientos y bucles. Ese apéndice es normativo, no informativo: no ilustra la especificación, la constituye. Los tres capítulos siguientes de este nivel son, en el fondo, una lectura comentada de sus tres partes centrales —el bucle principal, la selección de transiciones y el cálculo de conjuntos de estados—.

ℹ️
Recomendacion no significa adopcion

Conviene decirlo sin rodeos: como formato de intercambio, SCXML fracasó. Casi nadie escribe statecharts en XML a mano en 2026, y su nicho original —telefonía y control por voz— se evaporó. Pero un estándar puede fallar en su capa de transporte y triunfar en su capa semántica, y eso es exactamente lo que pasó. Lo que sobrevivió no fueron las etiquetas sino el apéndice: un procedimiento inequívoco que cualquier lenguaje puede implementar y contra el que cualquier implementación puede ser medida.

Anatomía de un documento: el vocabulario completo

Un documento SCXML es un árbol de estados con contenido ejecutable colgando de él. Su vocabulario es corto y casi todo te resultará familiar, porque lo has estado usando bajo otros nombres durante nueve niveles.

📜

Estructura

scxml como raíz, state para el estado simple o compuesto, parallel para las regiones ortogonales, final para el estado terminal, history con su atributo type shallow o deep, e initial para el hijo por defecto.

Transiciones

transition con event, cond y target. Sin event es una transición sin evento; sin target, una transición interna que solo ejecuta acciones. El atributo type distingue external de internal.

🧮

Datos y acciones

datamodel con sus elementos data, más el contenido ejecutable: assign, raise, send, cancel, log, script, if con elseif y else, y foreach.

🔌

Actores externos

invoke para delegar en otra máquina o servicio, con finalize para procesar su respuesta antes de que la máquina la vea, y donedata para el valor de salida de un estado final.

Lo notable de esa lista es lo corta que es. Un lenguaje capaz de describir el control de una centralita telefónica, la interfaz de un vehículo o el flujo de una compra cabe en veinte elementos, y la razón es que casi toda su expresividad viene de la composición y no del vocabulario: anidar estados, poner regiones en paralelo y colgar contenido ejecutable de los puntos correctos basta para cubrir el dominio entero. Es la misma economía que hace que los lenguajes funcionales pequeños compitan con los grandes.

Un ejemplo mínimo con reintentos concentra casi todo el vocabulario en veinte líneas.

<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
       datamodel="ecmascript" initial="inactivo">
  <datamodel>
    <data id="intentos" expr="0"/>
  </datamodel>

  <state id="inactivo">
    <transition event="FETCH" target="cargando"/>
  </state>

  <state id="cargando">
    <onentry>
      <assign location="intentos" expr="intentos + 1"/>
      <send event="TIMEOUT" delay="5s" id="reloj"/>
    </onentry>
    <onexit>
      <cancel sendid="reloj"/>
    </onexit>
    <transition event="done" target="exito"/>
    <transition event="error" cond="intentos &lt; 3" target="cargando"/>
    <transition event="error" target="fallo"/>
  </state>

  <final id="exito"/>
  <state id="fallo"/>
</scxml>

Dos detalles merecen atención. El primero es que las dos transiciones con event="error" están ordenadas: la condicional aparece antes, y por eso gana mientras se cumpla. Ese desempate por orden documental es una regla normativa que la lección 3 desarrollará. El segundo es el &lt; dentro de la condición: la sintaxis XML obliga a escapar el operador menor que, lo cual ilustra por qué el formato nunca conquistó a nadie. La semántica es elegante; el transporte, no.

Hay una tercera lectura, más sutil, en el par formado por el send con retardo y el cancel en la salida. Ese idioma —programar un temporizador al entrar y cancelarlo al salir— es la forma canónica de expresar un plazo asociado a un estado, y SCXML la deja explícita en lugar de esconderla tras un atajo. XState la esconde con after, que es más cómodo y estrictamente equivalente. Ver la versión desplegada ayuda a entender por qué un after desaparece al abandonar el estado: no es magia del framework, es un cancel que alguien escribió por ti.

Por qué XState se apoya en SCXML sin hablar XML

XState no lee XML en su núcleo, y sin embargo su documentación se ha definido durante años por conformidad con SCXML. La razón es estratégica antes que técnica: implementar una semántica ya normalizada y verificada por una batería pública de tests le ahorró al proyecto discutir cada decisión de diseño desde cero, y le dio un argumento de autoridad frente a la pregunta inevitable de qué pasa en los casos raros. La respuesta es siempre la misma: lo que dice el apéndice D.

El beneficio para quien usa la librería es menos obvio y más duradero. Significa que el conocimiento que adquieres al aprender XState no es conocimiento de una API sino de un modelo computacional, y que por tanto se transfiere. Significa también que cuando la documentación calla —y toda documentación calla en algún momento— existe una fuente superior a la que acudir en lugar de recurrir a la experimentación a ciegas. Pocas librerías de gestión de estado ofrecen algo parecido: en la mayoría, el comportamiento en los casos límite es lo que haga la implementación actual, y eso puede cambiar en la siguiente versión menor sin que nadie lo considere un cambio de contrato.

Elemento SCXML Equivalente en XState v5 Concepto que fija
state con hijos states anidados Jerarquía y refinamiento
parallel type: 'parallel' Regiones ortogonales
history type="deep" type: 'history', history: 'deep' Memoria de configuración
onentry y onexit entry y exit Acciones de ciclo de vida
raise raise Cola interna, prioridad alta
send con delay sendTo y after Cola externa y temporizadores
invoke con finalize invoke con onDone Delegación en actores
cond guard Predicado de habilitación
done.state.id xstate.done.state.id Fin de un estado compuesto

La tabla revela también dónde XState se aparta. Los nombres de eventos automáticos se renombraron al espacio xstate. en la versión 5, el modelo de datos de SCXML se sustituyó por el context con assign, y las expresiones dejaron de ser cadenas evaluadas para ser funciones de JavaScript con tipos. Son divergencias de superficie: ninguna toca el algoritmo. Lo que XState hereda íntegro es el orden de ejecución, la resolución de conflictos, el cálculo de conjuntos de entrada y salida, y la disciplina de ejecución hasta completar.

El linaje tiene además un eslabón intermedio que conviene conocer. Antes de XState existió SCION, un intérprete de SCXML escrito en JavaScript que demostró que la semántica del W3C podía ejecutarse en el navegador con rendimiento razonable, y que sirvió de referencia técnica y conceptual para lo que vino después. La contribución de XState no fue inventar la semántica sino domesticar su ergonomía: sustituir el XML por objetos literales, añadir inferencia de tipos que hace imposible enviar un evento inexistente, y envolver todo en herramientas de visualización e inspección. Es una historia frecuente en el software: el estándar aporta las decisiones difíciles y la librería aporta que quepan en el día a día.

📝
La conformidad se demuestra, no se declara

Junto a la Recomendación, el W3C publicó una suite de conformidad con más de un centenar de casos, cada uno un documento SCXML diminuto que termina en un estado llamado pass o en uno llamado fail según cómo interprete el runtime un punto concreto del algoritmo. Ejecutar esa suite convierte la afirmación seguimos la semántica de SCXML en una medición reproducible en lugar de una declaración de intenciones. Es la diferencia entre una especificación con dientes y un documento de buenas prácticas.

💡
Donde mirar cuando la documentacion no responde

Cuando te encuentres con un comportamiento de XState que la documentación no explica —qué ocurre si dos regiones paralelas responden al mismo evento, en qué orden se ejecutan las acciones de salida de una jerarquía profunda, si un raise dentro de un entry se procesa antes de estabilizar—, la Recomendación de SCXML es la fuente primaria. Su apéndice D no es un documento de fondo: es literalmente el programa que estás ejecutando, escrito en un pseudocódigo legible.

Un estandar es una decision tomada de una vez y para siempre

La tentación al leer esta lección es archivarla como curiosidad histórica: qué interesante que exista un XML del que nadie ha oído hablar. Pero lo que SCXML representa es algo mucho más raro y más valioso que un formato, y es la razón por la que este nivel existe. Un statechart no es un diagrama; es un objeto matemático que necesita una función de interpretación para significar algo, y esa función admite decenas de definiciones razonables que producen comportamientos incompatibles. Durante casi veinte años el campo vivió con esa ambigüedad, y la consecuencia práctica fue que ningún diagrama era portable, ninguna verificación era transferible y ninguna discusión sobre el comportamiento correcto podía cerrarse con otra cosa que la autoridad de un fabricante. Lo que hizo el W3C fue elegir. No descubrir la semántica verdadera —no la hay— sino fijar una, escribirla como algoritmo ejecutable, publicarla y someterla a una suite de conformidad que convierte la conversación en una cuestión empírica: tu intérprete pasa los tests o no los pasa. Ese gesto transforma el dominio entero. Cuando escribes una máquina en XState y te preguntas qué hará ante un evento ambiguo, no estás consultando una opinión de diseño ni la intuición de un mantenedor: estás consultando una decisión colectiva tomada en 2015 tras diez años de borradores, que se comporta igual en JavaScript, en Java, en C++ y en Python. Eso es lo que separa una herramienta de una disciplina. La biblioteca la puedes cambiar mañana; la semántica, si la entiendes, te acompaña a través de todas las bibliotecas que uses el resto de tu carrera, porque no es una propiedad de la biblioteca sino del objeto que la biblioteca manipula.

⚔️ Traducir en las dos direcciones
  1. Toma la máquina de reintentos en XML de esta lección y escríbela en XState v5 con setup. Comprueba que el orden de las dos transiciones con evento error se conserva en tu array de transiciones.
  2. Localiza en la Recomendación de SCXML la lista de elementos de contenido ejecutable y marca cuáles tienen equivalente directo en XState v5, cuáles tienen equivalente aproximado y cuáles no existen.
  3. Escribe en XML una máquina con un parallel de dos regiones y tradúcela a XState. Anota qué información se pierde y qué se gana en cada dirección de la traducción.
  4. Busca en la documentación de XState v5 tres nombres de eventos automáticos del espacio xstate. y encuentra su ancestro en la Recomendación. Explica por qué el cambio de nombre no altera la semántica.
  5. Argumenta en un párrafo por qué un estándar puede fracasar como formato y triunfar como especificación, usando SCXML como caso y buscando un segundo ejemplo fuera de este dominio.