UVL feature model

The UVL (Universal Variability Language) file is the formal model of an SPL’s variability. It defines which features exist, whether they are mandatory or optional, and what constraints govern their combination. The UVL lives in the shared splent_catalog/ repository at workspace root — not inside individual products.


Table of contents

  1. What it governs
  2. Location
  3. Format
    1. Features block
    2. Constraints block
  4. Who reads the UVL
  5. Lifecycle of the UVL
    1. Fetching from UVLHub
    2. Creating from scratch
    3. Fixing constraints
    4. Validating
  6. UVL vs pyproject.toml
  7. See also

What it governs

pyproject.toml declares which features a product uses and at which version. The UVL declares which combinations are valid — structure, optionality, and cross-tree constraints.

Together they answer two different questions:

Question Answered by
What features does this product include? pyproject.toml
Is this combination of features valid? UVL

The UVL does not contain version numbers. Versions are managed exclusively in pyproject.toml via feature:attach.


Location

The UVL lives in the SPL catalog — a shared splent_catalog/ git repository at workspace root. Each SPL has its own directory containing a metadata.toml and the .uvl file:

<workspace>/
├── splent_catalog/                          <- shared catalog repo
│   └── <spl_name>/
│       ├── metadata.toml                    <- DOI, mirror, description
│       └── <spl_name>.uvl                   <- the feature model
├── <product_a>/
│   └── pyproject.toml                       <- spl = "<spl_name>"
└── <product_b>/
    └── pyproject.toml                       <- spl = "<spl_name>" (same SPL)

Products reference an SPL by name in pyproject.toml:

[tool.splent]
spl = "sample_splent_app"

The catalog’s metadata.toml holds the UVLHub metadata:

mirror = "uvlhub.io"
doi    = "10.5281/zenodo.19219696"

Multiple products can derive from the same SPL. Constraints are properties of the feature model (the SPL), not of individual products.

Legacy support: Products that still use [tool.splent.uvl] in their pyproject.toml (with the UVL file in product/uvl/) continue to work. All UVL commands resolve from the catalog first, then fall back to the legacy per-product location.


Format

UVL is a domain-specific language for variability modelling. A typical SPLENT product model looks like this:

features
    sample_splent_app
        mandatory
            auth {org 'splent-io', package 'splent_feature_auth'}
        mandatory
            public {org 'splent-io', package 'splent_feature_public'}
        optional
            redis {org 'splent-io', package 'splent_feature_redis'}
        optional
            mail {org 'splent-io', package 'splent_feature_mail'}
        optional
            confirmemail {org 'splent-io', package 'splent_feature_confirmemail'}
        optional
            profile {org 'splent-io', package 'splent_feature_profile'}
        optional
            reset {org 'splent-io', package 'splent_feature_reset'}

constraints
    profile => auth
    confirmemail => mail
    reset => mail

Features block

Each feature is declared as mandatory or optional under the product root. The {org, package} attributes link the UVL name to its SPLENT package identity.

Constraints block

Cross-tree constraints express dependencies between features:

  • profile => auth — selecting profile requires auth
  • confirmemail => mail — selecting confirmemail requires mail

These constraints are enforced by product:validate before derivation.


Who reads the UVL

Consumer What it reads Why
product:validate Full model + constraints Validates that the product’s feature selection satisfies all constraints (uses Flamapy)
feature:order Feature tree + constraints Resolves the topological load order (dependencies load first)
db:seed Feature tree + constraints Runs seeders in topological order
splent_framework (FeatureLoadOrderResolver) Feature tree + constraints Determines runtime feature registration order
product:validate Indirectly (via load order) Checks inter-feature contract conflicts in dependency order

Lifecycle of the UVL

Fetching from UVLHub

If the SPL’s UVL is already published on UVLHub, fetch it:

splent spl:fetch

This downloads the canonical model into splent_catalog/<spl_name>/ using the DOI declared in the catalog’s metadata.toml.

Creating from scratch

For new SPLs, use spl:create <name> (available in detached mode) to scaffold the catalog entry at splent_catalog/<name>/. Edit the .uvl file manually, then publish to UVLHub and add the DOI to metadata.toml.

Fixing constraints

spl:add-constraints writes changes to the catalog, not to the product. Constraints are properties of the SPL’s feature model — they are shared across all products that derive from it.

Validating

Run product:validate every time you add or remove a feature:

splent product:validate
OK: configuration is satisfiable.

If the check fails, the product cannot be derived.


UVL vs pyproject.toml

A common question: why two files?

  • pyproject.toml is the operational truth — it tells the system exactly what to install and run.
  • The UVL is the formal truth — it proves that the chosen configuration is valid according to the product line model.

Both are required. A product with a valid pyproject.toml but an invalid UVL configuration will be rejected at derivation time. A product with a valid UVL but missing feature entries in pyproject.toml will fail at sync time.


See also


Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es