Conformidad que rechaza

Una prueba razonable separa una ontología de un diagrama con etiquetas: ¿puede el artefacto prohibir algo? Una ontología sin axiomas, sin validación, sin intención arquitectónica es un glosario dibujado como grafo. Describe, pero no puede rechazar. Si Vercy es solo eso, la crítica acierta.

Por eso esta página responde a la prueba directamente, con un sí y una demostración que usted puede ejecutar. La conformidad en Vercy se impone, no decora. Existe un programa que lee un modelo, lo declara inválido y termina con código distinto de cero nombrando la regla que se ha roto. Abajo está exactamente qué programa, exactamente qué regla y un rechazo resuelto paso a paso.

La conformidad es una barrera, no una descripción

El registro vivo, publicado en github.com/ver-cy/registry, es la instancia en marcha del perfil ELMM. Su vía de escritura es un pull request, y la barrera de admisión en esa vía es la integración continua: ci/run.py ejecuta siete comprobaciones fail-closed en orden, y una sola comprobación en rojo bloquea la fusión. Fail-closed significa que el valor por defecto es el rechazo: un modelo se admite solo si sobrevive a todas las comprobaciones, no se admite mientras nadie objete.

Las siete comprobaciones, cada una terminando con código distinto de cero y una regla normativa nombrada en la primera violación:

Esto no es una promesa sobre el comportamiento: es el comportamiento. La barrera es el código, y el código es público.

La comprobación de integridad del grafo, regla por regla

check_graph es donde ocurren la mayoría de los rechazos estructurales. Impone seis reglas, cada una con su propio diagnóstico y su propio identificador ELMM:

  1. Un solo nodo por identidad principal (ELMM-I17): no hay dos registros que compartan un id de registro.
  2. Integridad referencial (ELMM-I19): cada extremo de arista, from y to, es el id de una entrada registrada.
  3. Cobertura de exportación (ELMM-I11, ELMM-I19): todo tipo que nombra una arista aparece en los exports del registro destino. El grafo es calculable estáticamente solo a partir de los registros, así que una referencia a un tipo que el destino no exporta se rechaza antes del momento de resolución.
  4. Acuerdo del mínimo declarado (ELMM-I11): donde el requires de un registro nombra el mismo destino y tipo que una arista, el declared_min de la arista es igual a ese min_version. Bajo Selección de Versión Mínima la arista es la única entrada del resolutor, así que registro y arista deben coincidir.
  5. Aislamiento del núcleo (ELMM-I18): ninguna arista composes sale del nodo del núcleo. El núcleo no orquesta nada: su conocimiento de los modelos viene del registro, nunca de aristas salientes.
  6. Aciclicidad (ELMM-I16): el subgrafo composes es un grafo dirigido acíclico.

Cada una de estas puede, por sí sola, poner en rojo un árbol verde.

Un rechazo resuelto paso a paso

Tome la regla 3, cobertura de exportación, y rómpala a propósito.

Suponga que el único Panorama gobernado, vercy.plmm, declara que referencia un tipo budget-line propiedad del modelo de unidades organizativas vercy.oumm. En mmdg/edges.json un autor añade:

{
  "from": "vercy.plmm",
  "to": "vercy.oumm",
  "edge_type": "references",
  "declared_min": "0.1.0",
  "compositional_role": "R4",
  "kinds": ["budget-line"]
}

La arista es válida según el esquema: tiene todos los campos obligatorios, así que check_schema la deja pasar. Ambos extremos están registrados, así que la integridad referencial pasa. Se lee como una afirmación perfectamente bien formada. Pero vercy.oumm no exporta budget-line. Sus exportaciones son org-unit, reporting-line, established-position y unit-mandate; budget-line no está en ninguna. La arista afirma una dependencia de un significado que el destino nunca publicó.

check_graph rechaza. La subcomprobación de cobertura de exportación recorre cada arista, toma el conjunto exports del destino y falla en el primer tipo nombrado que no esté en él. Emite el conjunto completo de exportaciones del destino, ordenado, para que quien lo lea vea exactamente qué se publicó y qué no. La ejecución termina con código distinto de cero y este diagnóstico:

check_graph: FAIL
edge #N (vercy.plmm -references-> vercy.oumm) references kind 'budget-line'
which is not in vercy.oumm exports ['established-position', 'org-unit',
'reporting-line', 'unit-mandate'] (ELMM-I11, export coverage)

La fusión queda bloqueada. No señalada, no advertida: bloqueada. ci/run.py devuelve un código de salida distinto de cero y el pull request no puede aterrizar. Para arreglarlo, el autor o hace que vercy.oumm exporte de verdad budget-line, que es un cambio real que el modelo propietario debe publicar y sostener, o deja de reclamar una referencia que nunca le fue concedida. El registro no dejará que un modelo dependa de un significado que otro modelo no ha exportado. Eso es algo que el artefacto prohíbe.

La misma forma de rechazo existe en toda la barrera. Una composición cíclica, en la que un Panorama compone un modelo que transitivamente lo compone de vuelta, se rechaza por aciclicidad (ELMM-I16). Una arista hacia un modelo inexistente se rechaza por integridad referencial (ELMM-I19). Un mínimo en requires que discrepe del declared_min de su arista se rechaza por acuerdo del mínimo declarado (ELMM-I11), porque de lo contrario el resolutor elegiría una versión contra la que el registro nunca se validó. Un registro que forzase una edición del núcleo se rechaza por la garantía de cambio cero (ELMM-I7). Un nombre de archivo con fecha se rechaza por la convención de nombres (S1). Un resolutor cuyas dos ejecuciones divergen se rechaza por determinismo (ELMM-I23). En cada caso la regla es la razón, el identificador está en el mensaje y el código de salida no es cero.

El patrón es lo importante: cada rechazo nombra una regla normativa a la que se puede apuntar el modelo, con la que se puede discutir y contra la que se puede corregir. No hay rechazo silencioso ni rechazo por gusto. Rompa la regla, obtenga el código de salida, lea el identificador.

Más allá del registro: los validadores de modelo

El registro controla las relaciones entre modelos. Cada modelo lleva sus propias barreras. El Meta-Modelo Colectivo, publicado y versionado en github.com/ver-cy/collective-meta-model, incluye un validador de nodo que ejecuta las barreras de V0 a V2 más las comprobaciones específicas del CMM y rechaza una instancia rota: un miembro sin colectivo, una concesión de autoridad sin otorgante, un mandato que no cierra ningún bucle de rendición de cuentas. El registro de esa modelo consigna la validación V2 como su nivel de conformidad, y el registro vale lo que valga el validador que lo respalda. El validador es la razón por la que el nivel es una afirmación y no un adorno.

El límite honesto

Hay que decir tres cosas con claridad.

Primero, hoy esto es conformidad a nivel de instancia de modelo. Las comprobaciones rechazan registros inválidos, aristas inválidas, resolución no determinista e instancias de modelo inválidas frente a sus validadores. Se ejecutan en CI en la vía de escritura y cualquiera puede ejecutarlas localmente: clone el registro de github.com/ver-cy/registry, ejecute python ci/run.py, rompa una regla y vea cómo falla. Eso es real, y basta para responder a la prueba.

Segundo, un servicio público de validación alojado, una página o un endpoint donde alguien de fuera suelte un modelo arbitrario y obtenga un veredicto sin clonar nada, todavía no existe. Es un punto abierto, y así se nombra. Hasta que salga, el rechazo es reproducible pero no está a un clic para un desconocido.

Tercero, quien clone el registro para reproducir el rechazo encontrará que una entrada de implementación de referencia sigue llevando un identificador afiliado a una marca comercial, anterior a la pasada de neutralidad. Es inerte para la demostración anterior, que usa solo los identificadores neutrales vercy.*, pero neutralizar esa entrada y su arista es un punto abierto nombrado en el registro.

Ninguna de estas salvedades cambia la respuesta a la prueba. Mientras un artefacto no pueda rechazar, es un glosario. Aquí está el rechazo: una comprobación nombrada, una salida distinta de cero, una regla normativa y una fusión que no ocurre. Ejecútelo usted mismo en la CI del registro y en los validadores de modelo. Ambos son públicos.