Skip to content

Precedence and conflicts

Precedence decides which layer wins when two of them set the same field. It is an integer on each Layer, compared numerically, with higher values applied later and therefore winning.

precedence: 30

An integer is used so that two layers can be compared directly. Ranking by matcher specificity, by directory depth or by discovery order produces an ordering that cannot be determined from the two layers alone.

Ordering is total and deterministic

Matching layers are sorted by precedence, and layers with equal precedence are sorted by the path of their Layer document relative to the fleet root.

base/layer.yaml                        0
environments/production/layer.yaml    10
sites/london/layer.yaml               20
roles/web/layer.yaml                  30
hosts/web-001/layer.yaml             100

The path tie-break gives the fold a defined order in every case. It does not resolve disagreements, and two layers of equal precedence setting the same field to different values are a conflict.

Resolution never depends on filesystem enumeration order, on the machine running the resolver, or on which host is being resolved beyond the matchers that selected it. The same repository at the same revision produces the same manifest for the same host every time.

Conflicts are errors

When two layers of equal precedence set the same field of the same resource to different values, resolution fails and no manifest is produced.

error: conflicting values for File[nginx-config].mode

  0640  roles/web            precedence 30
  0600  roles/web-tls        precedence 30

both layers match host web-001 at equal precedence

Selecting a winner would make the result depend on something not visible in the repository, applied as root on every host both layers match. Refusing to resolve reports the ambiguity when it is introduced.

Two layers setting the same field to the same value are not in conflict. The requirement is an unambiguous outcome, and several layers may mention a field.

Resolving a conflict means changing precedence so one layer is clearly the authority, or narrowing a matcher so the layers no longer overlap.

Host overrides

A single host is overridden by a layer with a high precedence and a matcher matching that host.

fleet/hosts/web-001/layer.yaml
datum: v1alpha1
type: Layer

name: host-web-001

precedence: 100
match:
  labels:
    datum/host: web-001

A host override is an ordinary layer, with no separate mechanism, per-host section or special syntax. Its contributions are recorded with provenance and it can conflict with another layer at the same precedence.

The conventional precedence of 100 sits well above the others, so a host override normally wins. A fleet-wide setting that has to take priority is given a higher number.

Traceability

Provenance is recorded per field as well as per resource, since a question is usually about one value.

Proposed command

datum explain is a proposed command and does not exist. The output below shows what the design has to be able to produce, which is the part being committed to.

$ datum explain File[nginx-config] --host web-001

File[nginx-config]   /etc/nginx/nginx.conf

contributed by
  roles/web        precedence  30   matched role=web
  hosts/web-001    precedence 100   matched datum/host=web-001

fields
  path     /etc/nginx/nginx.conf    roles/web
  owner    root                     roles/web
  group    root                     roles/web
  mode     0600                     hosts/web-001   overrides 0640 from roles/web
  source   files/nginx.conf         roles/web

requires
  Package[nginx]                    roles/web

Two things have to survive resolution. Every field retains the layer that set its final value and the values it displaced, and every layer retains the labels that caused it to match. The resolver does not discard either after merging.

Ordering by specificity

Ranking layers by matcher specificity was rejected.

A matcher matching three labels is not reliably more authoritative than one matching two. role: web with site: london and architecture: amd64 is more specific than datum/host: web-001 by any counting rule while selecting a broader set of hosts. Making specificity work requires weighting label keys against each other, which puts a ranking of label keys in the repository.