Skip to content

Mutation Sources

Every Config Unit carries a record, called MutationSources, of which change last set each individual value in its configuration data. Where a Revision is a point-in-time snapshot of a unit's data and a Mutation records the source of one granular change, MutationSources is the accumulated result: a per-path index of who-and-what most recently touched each field. It serves two purposes — an audit trail ("git blame" for your configuration) and the information ConfigHub's merge engine uses to decide how to combine changes from different sources.

MutationSources is read-only in the sense that it is maintained automatically as the unit changes; you don't edit it the way you edit configuration data. You can, however, adjust the per-path eligibility flags it stores (see Predicates, below).

What MutationSources records

MutationSources is organized to mirror the configuration data:

  • One entry per resource. A unit's data is a collection of resources (for example, Kubernetes objects). MutationSources has one entry per resource, identified by type and name, plus a stable identifier that follows the resource across name changes and across variants. Both current and prior names are retained as aliases, so a resource can still be matched after it is renamed.
  • A map of paths to changes. Within each resource entry is a map from configuration path (for example, spec.replicas, or a specific container's image) to information about the change that last set that path: the kind of change (added, updated, or deleted), a reference to the Mutation (and therefore the Revision, function, link, trigger, or other source) that made it, and an eligibility flag described below.

Internally these structures are referred to as a ResourceMutationList (the list of per-resource entries) and, within each, a PathMutationMap (the per-path index). You can see them on a unit with:

cub unit get --space my-space my-unit -o jq=.Unit.MutationSources

Because ConfigHub treats configuration as data rather than text, paths address individual fields and individual elements of merge-keyed lists (such as a container matched by name), not line numbers. This is what lets ConfigHub attribute and merge changes field-by-field.

Viewing mutation sources

The raw -o jq form above is exact but unwieldy. For a readable view, cub unit get <unit> -o mutations renders a unit's MutationSources as a per-resource diff, grouped by the Predicate flag so you can see at a glance which fields are protected and which a merge may overwrite:

  • Locally overridden (preserved during merges) — paths whose Predicate is false.
  • Eligible for upstream merges — paths whose Predicate is true.
cub unit get --space my-space my-unit -o mutations

Add --verbose to also show each field's value, which change last set it (function, merge source, link, or trigger), and a summary table of the contributing Mutations.

The same -o mutations flag previews a pending change before it is written — for example, the per-path effect of an upgrade — when added to cub unit update ... --dry-run; see the variants guide.

How merging uses MutationSources

When ConfigHub merges changes between related units — propagating an upstream change into a cloned variant via Upgrade, merging a range of changes from another unit, or resolving a link — it needs to tell two kinds of changes apart: changes that came from the source being merged, versus changes made independently in the target unit. The latter are local overrides and are preserved by default.

MutationSources is what makes this distinction possible. Because each path records which mutation last set it, the merge engine can recognize that, say, the downstream unit's replica count was set by a local function invocation rather than inherited from upstream, and therefore should not be overwritten by an upgrade.

There are two complementary mechanisms that use this information to protect local overrides:

  • A filter over mutation history (WhereMutation). The Upgrade Link created when you clone a unit carries a default WhereMutation that treats only changes originating from the clone or a prior upgrade/merge as eligible to be overwritten. Anything else — a hand edit, a function invocation, a needs/provides binding, a trigger — is preserved.
  • The stored Predicate flag on each path (used when no WhereMutation is supplied).

For the full description of the merge algorithm, the Upgrade and merge commands, and how overrides are detected and preserved, see the Creating and managing variants guide.

Predicates

Each path in MutationSources carries a boolean Predicate that records whether the path is eligible to be overwritten by a merge:

  • true — the value came from a clone, upgrade, or merge; a future merge may overwrite it.
  • false — the value is a local override (set by a hand edit, function, trigger, or needs/provides resolution) and is protected from being overwritten.

ConfigHub maintains these flags automatically as a unit changes. They matter most when a merge's override-preservation subtraction step is turned off (see the variants guide): in that mode, the stored Predicate flags are the sole mechanism deciding which paths a merge may overwrite.

You can adjust the flags directly to change which fields a future merge is allowed to overwrite — for example, to protect a field that would otherwise be eligible, or to re-open one you previously protected:

# Protect the downstream replica count from being overwritten by merges.
cub unit set-predicates my-unit \
  --predicate "apps/v1/Deployment:my-namespace/my-app:spec.replicas=false"

Changing predicates produces a new Revision only if a flag actually changes.

Provenance and audit

Independently of merging, MutationSources answers "what last changed this field, and why?" Each path points at the Mutation responsible, which in turn carries the source — an update, a function invocation (ad hoc, triggered, or part of a clone/upgrade), a link resolution, an import, and so on. Restoring a unit to a prior Revision restores its MutationSources too, so the provenance always reflects the state you restored.