Extensión BPMN lila: y política de ids
Fuente de verdad: LILA_MODELER_ESTRUCTURA.md, sección 4 (ADR-012 "Identidad de elemento y de proceso", ADR-013 "Dónde vive cada dato", ADR-014 "Un solo namespace de extensión, definido una sola vez") y sección 5 (ruta de lila.moddle.json en el repositorio). Este documento es la referencia operativa para implementar el parser/serializador (packages/engine/src/bpmn/parse.ts) y el descriptor moddle (packages/engine/src/bpmn/lila.moddle.json); no repite el razonamiento de las ADR, lo aplica.
Este documento se apega a ADR-012 y ADR-014; cualquier discrepancia entre este archivo y esas ADR la resuelve LILA_MODELER_ESTRUCTURA.md y se corrige aquí.
1. Namespace
xmlns:lila="https://lila-modeler.org/schema/bpmn/1"
Decidido en ADR-014. El IRI no necesita resolver (no hay nada publicado en esa URL) — solo debe ser estable y no cambiar antes de M4. El sufijo /1 es la versión del namespace, no la versión del proceso: crece de forma aditiva (se agregan elementos nuevos; nunca se quita ni se resignifica uno existente) mientras el namespace siga siendo /1. Un cambio incompatible requeriría /2 — no se anticipa antes de M4.
El namespace se declara una sola vez, en bpmn:definitions, y se usa igual en:
- el editor (
apps/web, víaBpmnModeler({ moddleExtensions: { lila } })), - la CLI y el motor (
packages/engine), - cualquier servidor futuro (
packages/server, M6).
Los tres leen el mismo descriptor: packages/engine/src/bpmn/lila.moddle.json (sección 5 del documento de estructura). No existe una segunda copia del descriptor en ninguna otra parte del repositorio.
Round-trip
bpmn-moddle preserva namespaces desconocidos al hacer saveXML tras importXML (verificado con archivos reales de BPSim, qbp y Bizagi — ver investigacion-2026-09-03/02-bizagi-simulacion.md y 03-editor-bpmn.md). Esto es lo que permite que lila:* sobreviva a una herramienta que no lo conoce (round-trip por Camunda Modeler, Signavio, ADORIS, etc.) sin que esa herramienta necesite el descriptor. Ese comportamiento está verificado para bpmn-moddle y bpmn-js —el núcleo de Camunda Desktop Modeler— en la sección 8, con y sin el descriptor. Si alguna herramienta que importe resultara no preservar namespaces ajenos, el plan B es un sidecar annotations.json keyed por id de elemento con el mismo vocabulario (mismos nombres de campo que los elementos lila:*), fuera del .bpmn; nada de lo verificado hasta ahora lo necesita.
2. Elementos v1
Todos los elementos de la extensión son elementos XML hijos, nunca atributos del elemento BPMN que documentan — la única excepción es que cada elemento lila:* sí puede tener sus propios atributos (p. ej. lila:responsibility tiene los atributos type y roleRef). La razón de usar elementos y no atributos en el punto de inserción es permitir listas: un bpmn:task puede tener varios lila:systemRef (usa más de un sistema), varios lila:input/lila:output, etc. Un atributo XML no puede repetirse en el mismo nodo.
Todos (salvo versionTag, ver más abajo) van dentro de bpmn:extensionElements del elemento BPMN que documentan (tarea, evento, gateway, lane, o el propio bpmn:process):
<bpmn:task id="Task_7f3k2q1" name="Revisar solicitud">
<bpmn:extensionElements>
<lila:responsibility type="R" roleRef="rol-1"/>
<lila:responsibility type="A" roleRef="rol-2"/>
<lila:systemRef ref="sys-crm"/>
<lila:documentRef ref="doc-solicitud"/>
<lila:input ref="doc-solicitud"/>
<lila:output ref="doc-solicitud-revisada"/>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1</bpmn:incoming>
<bpmn:outgoing>Flow_2</bpmn:outgoing>
</bpmn:task>
| Elemento | Atributos | Qué documenta | Apunta a |
|---|---|---|---|
lila:responsibility |
type (R|A|C|I), roleRef |
Matriz RACI del elemento: una fila por combinación responsable/rol. Un elemento puede tener varios lila:responsibility (varios roles, o el mismo rol con distinto type no tiene sentido pero no se valida como error — es warning). |
roleRef → id en el catálogo de roles (catalog.json, ver ADR-013). |
lila:systemRef |
ref |
Sistema/aplicación que interviene en el elemento. | id en el catálogo de sistemas. |
lila:documentRef |
ref |
Documento asociado al elemento (entrada, salida o solo referencia general). | id en el catálogo de documentos. |
lila:riskRef |
ref |
Riesgo asociado al elemento. | id en el catálogo de riesgos. |
lila:controlRef |
ref |
Control asociado al elemento (mitiga un riesgo). | id en el catálogo de controles. |
lila:kpiRef |
ref |
Indicador que mide el elemento. | id en el catálogo de KPIs. |
lila:input |
ref |
Documento/dato que el elemento consume. Subconjunto semántico de documentRef con dirección explícita; puede coexistir con documentRef para el mismo id. |
id en el catálogo de documentos. |
lila:output |
ref |
Documento/dato que el elemento produce. | id en el catálogo de documentos. |
lila:versionTag |
value |
Ver sección 4 (clave de proceso). Único elemento que no cuelga de un elemento de flujo — cuelga de bpmn:process. |
— (valor libre, no referencia catálogo). |
Todas las referencias (roleRef, y los ref de systemRef/documentRef/riskRef/controlRef/kpiRef/input/output) apuntan a ids del catálogo (catalog.json, fuera del .bpmn — ADR-013). Una referencia colgante (id que no existe en el catálogo) es un warning de lint, no un error de validación — el catálogo puede completarse después del diagrama.
versionTag va como hijo de bpmn:extensionElements de bpmn:process (no de bpmn:definitions ni de una tarea):
<bpmn:process id="credito-solicitud" isExecutable="false">
<bpmn:extensionElements>
<lila:versionTag value="1.3.0"/>
</bpmn:extensionElements>
...
</bpmn:process>
Patrón calcado de zeebe:versionTag (Camunda 8), citado como precedente en ADR-012.
Atributos extendidos (#509)
Propiedades definidas por el usuario para cada tipo de elemento, como las de Bizagi Modeler («SLA»,
«Sistema dueño», «Nivel de riesgo»…): el modelador define un atributo una vez para un tipo de
elemento y lo rellena en cada elemento de ese tipo. Las dos mitades viven en el .bpmn, así que
viajan con el proceso y el contenedor del proyecto no cambia.
<bpmn:process id="credito-solicitud" isExecutable="false">
<bpmn:extensionElements>
<lila:attributeDefinition id="Attr_k2m8p1q" name="SLA (h)" type="number" appliesTo="task" default="24"/>
<lila:attributeDefinition id="Attr_a91nc0x" name="Nivel de riesgo" type="list" appliesTo="task">
<lila:option value="Bajo"/>
<lila:option value="Alto"/>
</lila:attributeDefinition>
</bpmn:extensionElements>
<bpmn:task id="Task_7f3k2q1" name="Revisar solicitud">
<bpmn:extensionElements>
<lila:attributeValue ref="Attr_a91nc0x" value="Alto"/>
</bpmn:extensionElements>
</bpmn:task>
</bpmn:process>
| Elemento | Atributos | Dónde |
|---|---|---|
lila:attributeDefinition |
id (NCName, Attr_<sufijo>), name, type (text|number|list|date), appliesTo (task|gateway|event|subProcess|lane|process), default opcional; una list lleva sus opciones como hijos lila:option value="…" |
extensionElements de la bpmn:collaboration si el diagrama la tiene; si no, de su único bpmn:process (el ejemplo de arriba). Los lectores las aceptan también en cualquier elemento raíz (el proceso de un pool, como las escribían los primeros archivos) y toman cada id una vez, el sitio canónico primero; el editor las lleva al sitio canónico en el siguiente guardado de su diálogo. |
lila:attributeValue |
ref (el id de la definición), value |
extensionElements del elemento que describe. |
appliesToagrupa tipos BPMN:taskes todo*Task;gateway, todo*Gateway;event, todo*Event, eventos de borde incluidos;subProcessessubProcess,transaction,adHocSubProcessycallActivity;laneeslaneyparticipant(el pool);processesbpmn:process. Flujos, datos y anotaciones de texto no llevan.- Los valores son texto en el XML y se validan, nunca se coaccionan (
validateAttributeValueenpackages/engine/src/bpmn/attributes.ts): unnumberes un decimal simple con punto (4.5o-2; no4,5,4.,+5,.5ni1e3); unadatees unAAAA-MM-DDque existe (años por debajo de 100 incluidos); el valor de unalistes una de sus opciones. La cadena vacía significa «sin rellenar» y no se escribe. El editor escribe números y fechas al salir del campo o con Intro, y solo si encajan, así que un24,5a medio teclear nunca deja24escrito. - Un elemento sin valor muestra el
defaultde la definición, que no se copia al elemento. - Los valores apuntan a la definición por
id, nunca por nombre, así que renombrar una definición los conserva. Aun así el editor pregunta antes de renombrar, cambiar de tipo, quitar opciones o borrar una definición que ya tiene valores en algunos elementos, nombrando las opciones quitadas y ofreciendo vaciar solo los valores que ya no encajan. Un valor cuya definición ya no está (editado a mano, otra herramienta) se conserva: se enseña con surefen el panel y en el documento del proceso, nunca se pierde; varios valores del mismo atributo en un elemento se enseñan todos. - Las definiciones no se mueven cuando entran o salen pools: añadir el primer pool o borrar el
último las lleva a la nueva raíz, borrar un pool cuyo proceso todavía las tenía las pasa antes a
la colaboración, y pegar un pool nunca las copia (repetiría cada
id). Una tarea dentro de un subproceso colapsado ve las mismas definiciones que el resto del diagrama. - El documento del proceso (Word/HTML) pone cada atributo rellenado (el valor propio o, si no, el de por defecto) como una línea con etiqueta bajo su elemento: el proceso y su pool bajo la descripción, cada carril bajo su encabezado, cada tarea, compuerta, evento y subproceso (las actividades de llamada incluidas, por su tipo BPMN) en su sección.
- Un modelo sin atributos extendidos se escribe byte a byte como antes; uno con ellos se abre sin
avisos en una herramienta que no tiene el descriptor
lila, y vuelve intacto (sección 8).
Qué NO es v1
Los parámetros de simulación (processingTime, resources, interTriggerTimer, etc.) no son parte de esta extensión — viven en *.scenario.json, separados del .bpmn (ADR-007, ADR-013; formato completo en SCENARIO_FORMAT.md). lila: documenta el proceso (RACI, sistemas, documentos, riesgos, controles, KPIs, versión); no lo parametriza para simular.
3. Política de ids (ADR-012)
Id de elemento
- El id de cada elemento BPMN (
bpmn:task@id,bpmn:sequenceFlow@id, etc.) es la única clave para colgar datos de negocio o de simulación. Nunca el nombre visible (name). - Formato: NCName válido (XML
Namesin:),<PrefijoPorTipo>_<sufijo>, p. ej.Task_7f3k2q1,Gateway_a91nc0x,Flow_k2m8p1q. Los ids del editor traen el sufijo del propio modelador; cuando es el motor quien tiene que acuñar uno (la rama de colisión del importador), el sufijo es un contador determinista comprobado contra los ids ya ocupados (Task_2,Task_3, …), así que importar dos veces el mismo archivo nunca da ids distintos (#326). - Prefijo por tipo (no exhaustivo, crece con el IR):
Start_,End_,Task_,Gateway_(XOR/OR/AND comparten prefijo; el tipo exacto vive en el IR, no en el id),Timer_,Flow_,SubProcess_. - Nunca se regenera un id existente al importar, exportar o renombrar el elemento (renombrar cambia
name, noid). Regenerar el id rompería cualquier referencia externa: entradas de*.scenario.jsonkeyed por id, filas de event log, referencias de catálogo. - Se genera un id nuevo al copiar/pegar un elemento — un elemento copiado es una entidad distinta y no debe arrastrar los datos (
lila:*, escenario) del original bajo el mismo id. - Sanitización reversible para ids ajenos no-NCName: algunas herramientas (Bizagi entre ellas) pueden emitir ids que no son NCName válidos. Al importar, Lila sanitiza esos ids a NCName y guarda el mapa
idSanitizado → idOriginalenir.source.originalIds(ver la forma deProcessIRen la sección 6 del documento de estructura), de modo que un re-export pueda restaurar el id original si la herramienta de destino lo necesita. La sanitización es determinista (mismo id ajeno → mismo id sanitizado) para que reimportar el mismo archivo no genere ids distintos cada vez.
El editor aplica el mismo sanitizeXmlIds del motor antes de entregar el documento a bpmn-js y
conserva el mapa por instancia de modelador. Al exportar, restaura en una sola pasada tanto las
declaraciones como las referencias (sourceRef, targetRef, default, bpmnElement y referencias
textuales), incluidas las de BPMNDI. La apertura se prepara en una instancia candidata y solo
reemplaza el lienzo activo cuando la importación completa termina; un XML mal formado o sin diagrama
renderizable no sustituye el XML, selección, servicios ni historial anteriores. Si el lector reportó
una pérdida semántica —por ejemplo, una referencia topológica rota— la exportación exige una decisión
visible con el detalle del aviso, porque el árbol serializado ya no puede reconstruir ese contenido.
Id de proceso
- Clave lógica de un proceso:
bpmn:process@id(slug ASCII) +lila:versionTag. Ejemplo:credito-solicitud+1.3.0. Es la clave que identifica "el mismo proceso, versión X" a través de reimportaciones y ediciones — no es soloprocess@id, porque dos versiones del mismo proceso de negocio pueden (y en general deben) coexistir como archivos o commits distintos con el mismoprocess@id. bpmn:process@idse genera igual que cualquier otro id de elemento (NCName; ver arriba) pero se recomienda un slug ASCII legible (credito-solicitud, noProcess_7f3k2q1) porque además de clave técnica funciona como nombre de carpeta/archivo en el layout de proyecto.lila:versionTages una cadena libre (semver recomendado,1.3.0, pero no forzado por el esquema — un usuario puede versionar comov2,2026-Q3, etc.). Ausente por defecto; su ausencia no es error.
exporter / exporterVersion
Todo .bpmn que Lila escribe declara, en bpmn:definitions:
<bpmn:definitions
xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:lila="https://lila-modeler.org/schema/bpmn/1"
exporter="Lila Modeler"
exporterVersion="1.0.0-beta.1"
...>
exporterVersion es la versión de paquete de @lila-modeler/engine que generó el archivo (siempre la del motor, también cuando quien guarda es la app web: los dos atributos los escribe un único helper, marcarExportador en packages/engine/src/bpmn/ids.ts) — sirve para diagnosticar diferencias de comportamiento entre versiones del motor, igual que hacen bpmn-js y Camunda Modeler con sus propios exporter/exporterVersion. Bizagi, por comparación, no declara estos atributos en su export (verificado en 5 archivos reales — ver investigacion-2026-09-03/02-bizagi-simulacion.md), lo que hace imposible saber qué versión de Bizagi Modeler generó un archivo dado; Lila evita ese problema desde el día uno.
4. Descriptor moddle (ejemplo)
Vive en packages/engine/src/bpmn/lila.moddle.json (única definición — sección 5 del documento de estructura). Forma que tendrá (ejemplo v1, sujeto a los ajustes menores que exija bpmn-moddle en implementación):
{
"name": "Lila",
"uri": "https://lila-modeler.org/schema/bpmn/1",
"prefix": "lila",
"xml": {
"tagAlias": "lowerCase"
},
"types": [
{
"name": "Responsibility",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "type", "isAttr": true, "type": "String" },
{ "name": "roleRef", "isAttr": true, "type": "String" }
]
},
{
"name": "SystemRef",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "ref", "isAttr": true, "type": "String" }
]
},
{
"name": "DocumentRef",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "ref", "isAttr": true, "type": "String" }
]
},
{
"name": "RiskRef",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "ref", "isAttr": true, "type": "String" }
]
},
{
"name": "ControlRef",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "ref", "isAttr": true, "type": "String" }
]
},
{
"name": "KpiRef",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "ref", "isAttr": true, "type": "String" }
]
},
{
"name": "Input",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "ref", "isAttr": true, "type": "String" }
]
},
{
"name": "Output",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "ref", "isAttr": true, "type": "String" }
]
},
{
"name": "VersionTag",
"superClass": ["Element"],
"meta": { "allowedIn": ["bpmn:ExtensionElements"] },
"properties": [
{ "name": "value", "isAttr": true, "type": "String" }
]
}
]
}
Notas de implementación (no normativas, se resuelven en el ticket que crea el archivo real):
meta.allowedIndocumenta la intención (todos menosVersionTagvan en elextensionElementsde un elemento de flujo;VersionTagen el debpmn:process); bpmn-moddle no validaallowedInen tiempo de parseo — la validación real de "quién puede contener qué" la hacepackages/engine/src/bpmn/validate.ts.- No se usan
associationsporque ninguno de estos tipos necesita sustituir o extender un tipo BPMN existente; todos son elementos nuevos que cuelgan debpmn:extensionElements, que ya acepta cualquiervalues[]de un namespace declarado. - Todas las propiedades son
isAttr: true(atributos del elementolila:*, no hijos propios) — mantiene cada elemento en una sola línea XML y es suficiente para v1 porque ninguno necesita texto libre ni anidamiento.
5. Fragmento de ejemplo completo
bpmn:extensionElements de una tarea con responsabilidad RACI, referencias de catálogo y versión de proceso:
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions
xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:lila="https://lila-modeler.org/schema/bpmn/1"
id="Definitions_1"
exporter="Lila Modeler"
exporterVersion="1.0.0-beta.1"
targetNamespace="http://lila-modeler.org/schema/bpmn">
<bpmn:process id="credito-solicitud" name="Solicitud de crédito" isExecutable="false">
<bpmn:extensionElements>
<lila:versionTag value="1.3.0"/>
</bpmn:extensionElements>
<bpmn:startEvent id="Start_9k2m1qa" name="Solicitud recibida">
<bpmn:outgoing>Flow_a1</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Task_7f3k2q1" name="Revisar solicitud">
<bpmn:extensionElements>
<lila:responsibility type="R" roleRef="rol-1"/>
<lila:responsibility type="A" roleRef="rol-2"/>
<lila:systemRef ref="sys-crm"/>
<lila:documentRef ref="doc-solicitud"/>
<lila:input ref="doc-solicitud"/>
<lila:output ref="doc-solicitud-revisada"/>
<lila:kpiRef ref="kpi-tiempo-revision"/>
</bpmn:extensionElements>
<bpmn:incoming>Flow_a1</bpmn:incoming>
<bpmn:outgoing>Flow_a2</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="End_k9x3m2z" name="Fin">
<bpmn:incoming>Flow_a2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_a1" sourceRef="Start_9k2m1qa" targetRef="Task_7f3k2q1"/>
<bpmn:sequenceFlow id="Flow_a2" sourceRef="Task_7f3k2q1" targetRef="End_k9x3m2z"/>
</bpmn:process>
</bpmn:definitions>
Correspondencia con el catálogo referenciado (catalog.json, fuera de este documento — ver SCENARIO_FORMAT.md/LILA_MODELER_ESTRUCTURA.md sección 5 para su ubicación): rol-1, rol-2, sys-crm, doc-solicitud, doc-solicitud-revisada y kpi-tiempo-revision son ids que deben existir ahí; si no existen, validate(ir) emite un warning de referencia colgante por cada uno, no un error.
6. Consistencia con las ADR
- ADR-012 (identidad de elemento y de proceso): implementado en la sección 3 de este documento — NCName con prefijo por tipo, nunca regenerado, nuevo al copiar, sanitización reversible, clave de proceso =
process@id+versionTag,exporter/exporterVersionendefinitions. - ADR-014 (namespace único, definido una sola vez): implementado en las secciones 1, 2 y 4 — un solo IRI, un solo descriptor compartido por editor/CLI/servidor, elementos (no atributos en el punto de inserción) para permitir listas, crecimiento aditivo, round-trip verificado en headless en la sección 8 (no hizo falta el fallback a
annotations.json).
Si en el futuro alguna decisión de este documento entra en conflicto con una ADR nueva o revisada, gana la ADR y este documento se actualiza para reflejarla (nunca al revés).
7. Round-trip en la app web
La app web abre un .bpmn con bpmn-js y lo vuelve a escribir con saveXML, es decir con
bpmn-moddle serializando el árbol que bpmn-moddle pudo leer. Eso fija exactamente qué
sobrevive a abrir-y-exportar (LILA-192, apps/web/src/modelerXml.ts):
Se conserva
- Los ids originales del archivo, incluidos los que no son NCName. Al importar se sanean de forma reversible (sección 3) y al exportar se restauran uno a uno, en atributos, en texto y en las referencias del BPMNDI, con las comillas y las entidades del original.
- Los elementos
lila:de este documento y las extensiones ajenas (bizagi:y compañía): el descriptorlilava enmoddleExtensionsy el resto viaja como contenido genérico. - El diagrama (
bpmndi), la documentación, los nombres y la topología. exporter/exporterVersionendefinitions, que los reescribe siempremarcarExportador.
No se conserva
- Las referencias por id que apuntan a un elemento que el archivo nunca declara —
messageRef,dataStoreRef,categoryValueRef,dataObjectRef—: bpmn-moddle no las resuelve, no llegan al árbol y el archivo exportado ya no las lleva. Los fixtures deexamples/bizagi-exportsson un caso real. - Lo que el import descarta con un aviso de contenido no parseable o de referencia de topología sin resolver: si no entró en el modelo, no puede salir en el XML.
Cómo se avisa (nunca en silencio, que era la queja de LILA-192)
- La barra de estado enseña la lista completa como error —no como aviso—, con los ids: «N elementos o referencias se perderán al exportar: …» (LILA-193).
- Todo lo que escribe un .bpmn con pérdida pasa antes por el mismo diálogo, con esa misma lista y dos salidas: «Exportar .bpmn» ofrece «Exportar igualmente»/«Cancelar» y guardar el proyecto ofrece «Guardar igualmente»/«Cancelar». Cancelar no descarga ni escribe nada en disco.
autorizarExportacioncorta con un error cualquier exportación con pérdida que no traigaaceptarPerdida, es decir el sí explícito de ese diálogo: el XML que alimenta a la simulación —que el usuario no ve— nunca lo trae, y el snapshot de guardar solo lo trae después del sí.- En Electron, cancelar el diálogo al guardar devuelve «no se guardó» al cierre de la ventana, así que el cierre se cancela y no se pierde nada.
Nada de esto reescribe el serializador: la fidelidad byte a byte con el archivo de origen no es una promesa de la app, y conservar atributos rotos exigiría un serializador propio.
8. Round-trip en otras herramientas (LILA-068)
Toda la apuesta de ADR-014 —un namespace propio dentro del .bpmn, en vez de un sidecar— solo
vale si otra herramienta puede abrir un archivo de Lila, guardarlo y devolver los lila: intactos.
Verificado headless contra el par sobre el que está construido Camunda Desktop Modeler (es Electron
- bpmn-js; ver
investigacion-2026-09-03/03-editor-bpmn.md): bpmn-moddle 10.2.0 y bpmn-js 18.28.0, las versiones que instala este repositorio.
Lo que viaja es examples/pedido/model.bpmn con un elemento de cada tipo v1 (sección 2) escrito por
el propio escritor del motor —dieciocho elementos lila: (los atributos extendidos incluidos) repartidos en varios elementos
dueños, con repeticiones— y el round-trip corre dos veces: con lila.moddle.json, que es lo que hacen el
editor y la CLI de Lila, y sin él, que es lo que tiene una herramienta ajena (un namespace sin
declarar que bpmn-moddle conserva como contenido genérico). En los dos casos, y por las dos
librerías, el guardado devuelve:
- todos los elementos
lila:, colgando del mismo elemento dueño y con los mismos valores de atributo; - el namespace, declarado una sola vez en
bpmn:definitions; - la
bpmn:documentationde los elementos anotados, sus ids y el diagrama (bpmndi).
También aguanta si la otra herramienta escribe un prefijo propio (solo el IRI es normativo, sección 1), y el segundo guardado es idéntico al primero: de ahí en adelante el archivo es un punto fijo.
Pruebas: packages/engine/test/bpmn-roundtrip.test.ts (bpmn-moddle) y
apps/web/src/bpmnRoundtrip.test.ts (bpmn-js), con el archivo anotado y la comparación en
packages/engine/test/bpmn-roundtrip.fixture.ts. Lo que se compara es un inventario de los
elementos lila: leído del texto del XML, normalizado en prefijo y en orden de atributos, no el
archivo entero byte a byte: bpmn-moddle reformatea todo lo que reserializa, y la sección 7 ya dice
que la fidelidad byte a byte no es una promesa.
| Herramienta | Qué lee y escribe su XML | lila: tras abrir y guardar |
Cómo se comprobó |
|---|---|---|---|
| Camunda Desktop Modeler (y cualquier editor construido sobre las librerías de bpmn.io) | bpmn-js 18.28.0 sobre bpmn-moddle 10.2.0 | se conserva | round-trip headless sobre ese mismo núcleo, con y sin el descriptor (apps/web/src/bpmnRoundtrip.test.ts) |
| Cualquier herramienta sobre bpmn-moddle a secas (conversores, servidores, la CLI de Lila) | bpmn-moddle 10.2.0 | se conserva | packages/engine/test/bpmn-roundtrip.test.ts |
| Lila Modeler mismo (web y escritorio) | bpmn-js con moddleExtensions: { lila } |
se conserva | sección 7, más apps/web/src/exportar.test.ts |
| Signavio | propietaria, SaaS | sin verificar | no hay cuenta disponible |
| ADONIS | propietaria | sin verificar | no hay licencia disponible |
| Bizagi Modeler | propietaria | sin verificar | no hay licencia disponible; la dirección opuesta —que Lila conserve un bizagi: ajeno al abrir y exportar— la cubren los fixtures de examples/bizagi-exports en apps/web/src/exportar.test.ts |
Qué no cubre esto. No se manejó la interfaz de Camunda Desktop Modeler: la prueba headless pasa
por la mismísima instancia de moddle con la que bpmn-js lee y escribe el XML (importXML es
moddle.fromXML, saveXML es moddle.toXML, y nada entre ambas toca el árbol que se serializa),
pero no por su lienzo, que jsdom no sabe dibujar. Signavio y ADONIS no se probaron en absoluto, por
falta de acceso; si alguna descarta namespaces ajenos, los descarta para todos los elementos lila:
a la vez, que es justo lo que mediría el inventario de arriba.
El plan B sigue sin escribirse. El sidecar annotations.json que la sección 1 guarda como
respaldo no hace falta: ninguna herramienta verificada aquí descarta el namespace. Su ticket se
abre el día que se demuestre que una herramienta que importa lo tira, y el formato del archivo no
cambia antes de eso.