VERCY

Conformance that refuses

One reasonable test separates an ontology from a diagram with labels: can the artifact forbid anything? An ontology without axioms, without validation, without architectural intent is a glossary drawn as a graph. It describes; it cannot reject. If Vercy is only that, the criticism lands.

So this page answers the test directly, with a yes and a demonstration you can run. Conformance in Vercy is enforced, not decorative. There is a program that reads a model, finds it invalid, and exits non-zero naming the rule it broke. Below is exactly which program, exactly which rule, and one worked refusal.

Conformance is a gate, not a description

The live registry, published at github.com/ver-cy/registry, is the running instance of the ELMM profile. Its write path is a pull request, and the admission gate on that path is continuous integration: ci/run.py runs seven fail-closed checks in order, and a single red check blocks the merge. Fail-closed means the default is refusal: a model is admitted only if it survives every check, not admitted unless someone objects.

The seven checks, each exiting non-zero with a named normative rule on the first violation:

This is not a promise about behavior; it is behavior. The gate is the code, and the code is public.

The graph integrity check, rule by rule

check_graph is where most structural refusals happen. It enforces six rules, each with its own diagnostic and its own ELMM identifier:

  1. Single node per major identity (ELMM-I17): no two records share a registry id.
  2. Referential integrity (ELMM-I19): every edge endpoint, from and to, is a registered entry id.
  3. Export coverage (ELMM-I11, ELMM-I19): every kind an edge names appears in the target record's exports. The graph is statically computable from records alone, so a reference to a kind the target does not export is rejected before resolve time.
  4. Declared-min agreement (ELMM-I11): where a record's requires names the same target and kind as an edge, the edge's declared_min equals that min_version. The edge is the sole resolver input under Minimal Version Selection, so the record and the edge must agree.
  5. Kernel isolation (ELMM-I18): no composes edge leaves the kernel node. The kernel orchestrates nothing; its knowledge of models comes from the registry, never from outgoing edges.
  6. Acyclicity (ELMM-I16): the composes subgraph is a directed acyclic graph.

Each of these can turn a green tree red on its own.

One worked refusal

Take rule 3, export coverage, and break it on purpose.

Suppose the single governed Landscape, vercy.plmm, declares that it references a budget-line kind owned by the org-unit model vercy.oumm. In mmdg/edges.json an author adds:

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

The edge is schema-valid: it has every required field, so check_schema passes it. Both endpoints are registered, so referential integrity passes. It reads as a perfectly well-formed statement. But vercy.oumm does not export budget-line. Its exports are org-unit, reporting-line, established-position, and unit-mandate; budget-line is in none of them. The edge asserts a dependency on meaning the target never published.

check_graph refuses. The export-coverage sub-check walks every edge, takes the target's exports set, and fails on the first named kind absent from it. It emits the target's full export set, sorted, so the reader can see exactly what was and was not published. The run exits non-zero with this diagnostic:

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)

The merge is blocked. Not flagged, not warned, blocked: ci/run.py returns a non-zero exit code and the pull request cannot land. To fix it the author either makes vercy.oumm actually export budget-line, which is a real change the owning model must publish and stand behind, or stops claiming a reference that was never granted. The registry will not let a model depend on meaning that another model has not exported. That is a thing the artifact forbids.

The same shape of refusal exists across the gate. A cyclic composition, where a Landscape composes a model that transitively composes it back, is rejected by acyclicity (ELMM-I16). An edge to a model that does not exist is rejected by referential integrity (ELMM-I19). A requires minimum that disagrees with its edge's declared_min is rejected by declared-min agreement (ELMM-I11), because the resolver would otherwise select a version the record never validated against. A registration that would force a kernel edit is rejected by the zero-change guarantee (ELMM-I7). A dated filename is rejected by the naming convention (S1). A resolver whose two runs diverge is rejected by determinism (ELMM-I23). In each case the rule is the reason, the identifier is in the message, and the exit code is non-zero.

The pattern is the point: every refusal names a normative rule the model can be pointed at, argued with, and fixed against. There is no silent rejection and no rejection by taste. Break the rule, get the exit code, read the identifier.

Beyond the registry: the model validators

The registry gates relationships between models. Individual models carry their own gates. The Collective Meta-Model, published and versioned at github.com/ver-cy/collective-meta-model, ships a node validator that runs the V0 to V2 gates plus the model-specific CMM checks and refuses on a broken instance: a member without a collective, an authority grant with no grantor, a mandate that closes no accountability loop. The registration record for that model records V2 validation as its conformance level, and the record is only as good as the validator that backs it. The validator is the reason the level is a claim and not a decoration.

The honest boundary

Two things must be said plainly.

First, this is model-instance conformance today. The checks refuse invalid registry records, invalid edges, non-deterministic resolution, and invalid model instances against their validators. They are run in CI on the write path and can be run by anyone locally: clone the registry from github.com/ver-cy/registry, run python ci/run.py, break a rule, watch it fail. That is real, and it is enough to answer the test.

Second, a hosted public validation service, a page or an endpoint where an outsider drops in an arbitrary model and gets a verdict without cloning anything, does not exist yet. It is an open item, named as one. Until it ships, refusal is reproducible but not one-click for a stranger.

Third, a reader who clones the registry to reproduce the refusal will find that one reference-implementation entry still carries a commercial-affiliated identifier from before the neutrality pass. It is inert to the demonstration above, which uses only the neutral vercy.* ids, but neutralizing that entry and its edge is a named open item on the registry.

Neither caveat changes the answer to the test. Until an artifact can refuse, it is a glossary. Here is the refusal: a named check, a non-zero exit, a normative rule, and a merge that does not happen. Run it yourself in the registry CI and in the model validators. Both are public.