Skip to content

Reference expressions

Reference expressions let one authored value read immutable state produced elsewhere. They are self-contained objects and can appear in template-bearing fields supported by a unit kind.

Two uses of promotion

This page describes the field-level fromPromotion reference expression, which reads a source Unit's public spec. A Stack's artifactImports[].fromPromotion instead imports a validated artifact from source desired and observed state. StackTemplate acquisition is separate: fromGit resolves a repository source, while fromPromotion explicitly selects a source StackTemplate during promote; neither mode is implicit. See Stacks and StackTemplates.

Expression Reads Pointer scope Required selectors
fromReceipt Current producer receipt result Typed driver result unit; pointer defaults to ""
fromArtifact Named artifact resource Complete artifact document unit, name, apiVersion, kind; pointer defaults to ""
fromPromotion Desired unit in the pinned promotion source Source unit's public spec unit and pointer are independently optional
api_url:
  fromReceipt: {unit: infrastructure, pointer: /outputs/api_url}
image:
  fromArtifact:
    unit: application-images
    name: containers
    apiVersion: artifact.gitopsctr.io/v1
    kind: ContainerImages
    pointer: /images/application/uri
promoted_image:
  fromPromotion: {}

Receipt and artifact evidence is valid only while its receipt matches the producer's current desired unit. Before a value is read, the controller checks artifact identity, type, descriptor, media type, and digest. If required evidence is missing or stale, the consumer waits.

See Receipt lookup and Artifact lookup for the exact files, freshness checks, and pointer scope.

Promotion selectors

fromPromotion defaults to the target unit name and the containing field's JSON Pointer. Both selectors can be overridden independently:

Expression Source unit Source pointer
fromPromotion: {} Target unit name Containing field path
fromPromotion: {unit: release} release Containing field path
fromPromotion: {pointer: /inputs/release} Target unit name /inputs/release
fromPromotion: {unit: release, pointer: /inputs/release} release /inputs/release

An inferred pointer requires matching apiVersion and kind values. A cross-kind reference must specify pointer. pointer: "" selects the source unit's public spec. Resource metadata and driver identity are never exposed.

Once a promotion is active, a missing source unit, mismatched inferred kind, or unresolved pointer is an error rather than a waiting condition. Successful promotion inputs are fingerprinted as <source-unit>#<effective-pointer>, so multiple fields from one source unit are tracked independently.

dryFallback

Use dryFallback when a bootstrap or speculative plan needs a type-correct value before its promoted, observed, or artifact evidence exists:

image:
  fromArtifact:
    unit: application-images
    name: containers
    apiVersion: artifact.gitopsctr.io/v1
    kind: ContainerImages
    pointer: /images/application/uri
    dryFallback: registry.invalid/application@sha256:0000000000000000000000000000000000000000000000000000000000000000

The fallback is used only during dry resolution, including reconcile --plan and apply --dry, and only when the reference is unavailable. Normal apply and reconciliation never use it. Invalid expressions, type errors, and broken active promotions remain fatal. A fallback cannot hide them.

Fallback values use the same recursive template language as their containing field. They may be scalar, structured, explicitly null, or another reference:

endpoint:
  fromPromotion:
    dryFallback:
      fromReceipt: {unit: preview-infrastructure, pointer: /outputs/endpoint}

fromParameter is not allowed anywhere inside a projection-time fallback, including nested fallback objects. Stack parameters must be expanded before a structural projection is persisted.

When a fallback supplies the value, the unavailable reference contributes no fingerprint. A nested fallback reference that resolves successfully contributes its own normal fingerprint.