Skip to content

package runtime

import "github.com/cloudboss/unobin/pkg/runtime"

Package runtime is the execution engine linked into every compiled factory binary.

Owns:

  • DAG construction (implicit deps via reference; explicit via @depends-on)
  • Plan computation: refresh + drift + change detection + replace-because chains
  • Apply execution: parallelism cap (default 10), per-resource state writes, apply error UX
  • State model (snapshots, content-addressed, encrypted at rest)
  • Action semantics (triggered with @trigger; 'always' literal; @lock; @timeout)

Companion packages:

  • pkg/sdk/state - Backend contract that provider libraries implement
  • pkg/state/local and pkg/state/s3 - the filesystem and S3 backends
  • pkg/runner - the factory CLI that invokes runtime entry points

Constants

const DefaultParallelism = 10

DefaultParallelism is the in-flight cap apply uses when no explicit value is given on the Executor or in the plan file.

const PlanFormatVersion = 1

PlanFormatVersion is the schema version this package reads and writes for plan files.

const TriggerAlways = "always"

TriggerAlways is the literal an action uses to opt into running every time, regardless of stored state.

Variables

var ErrEvalNotFound = errors.New("not found")

ErrEvalNotFound is returned by Eval when an address or field cannot be resolved in the current scope. Plan callers may treat it as "known after apply"; apply re-evaluates against the live scope and surfaces a real failure when the reference truly is invalid.

var ErrInstanceGone = errors.New("instance no longer in iterable")

ErrInstanceGone is returned by ensureCompositeScope when a per- instance composite scope is requested for a key that the boundary's `@for-each` iterable no longer yields. Plan-time seeding of prior state treats this as a signal to skip rather than fail; orphan destroy steps for the missing instance still emit through the usual orphan path.

var ErrInterrupted = errors.New("apply: interrupted")

ErrInterrupted is returned by ApplyPlan when the executor's Drain channel was closed before all steps could be dispatched. The returned snapshot still reflects every step that completed before the drain, so re-plan plus apply will pick up the remainder.

var ErrNotFound = errors.New("resource not found")

ErrNotFound is returned by a resource's Read method when the resource is absent in the cloud. The runtime treats it as a request to recreate.

Functions

func ApplyBindings

func ApplyBindings(ctx *EvalContext, binds []lang.EachBinding)

ApplyBindings copies a constraint's iteration bindings onto the context so @each and any chained level name resolve during the element's evaluation.

func Changed

func Changed[T any](prior, current T) bool

Changed reports whether a field differs between its prior and current value. It compares by value, so a pointer field compares what it points at, and a state round trip that re-decodes an equal value is not a false positive.

func CompositeInputNames

func CompositeInputNames(n *Node) map[string]bool

CompositeInputNames returns the input names declared by a composite boundary.

func CoreFunctionSigs

func CoreFunctionSigs() map[string]typecheck.FuncSig

CoreFunctionSigs returns each @core function's signature, keyed by name, for compile-time existence, arity, and type checking.

func Decode

func Decode(v any, inputs map[string]any) error

Decode fills v's exported fields from the inputs map using `ub` struct tags. A field's key is the tag's name, or the kebab-cased field name when the tag has no name (or no tag at all). String values like "30s" decode into time.Duration fields. v must be a non-nil pointer to a struct.

func DirectParent

func DirectParent(addr string) string

DirectParent returns addr's parent state-ref segment path, or the empty string for a root segment. Unlike templateAddress, DirectParent preserves `['key']` segments so the result names a per-instance composite call site when one is present.

func DotPathString

func DotPathString(p *lang.DotPath) string

dotPathString renders a dotted reference back to its source form. Named segments are joined with `.`; indexed segments preserve the `['\']` form when the index is a string literal, and otherwise collapse to `[...]` so the path stays readable.

func EncodePlan

func EncodePlan(p *Plan) ([]byte, error)

EncodePlan renders a plan as JSON bytes for on-disk storage.

func Eval

func Eval(e lang.Expr, ctx *EvalContext) (any, error)

Eval reduces a parsed expression to a Go value. Supported are literals, bare identifiers (as their name string); array and object literals (recursive); and the `input.X[.Y...]` address form.

func RefAddress

func RefAddress(p *lang.DotPath) string

func Refs

func Refs(e lang.Expr) []string

Refs returns the addresses an expression depends on, in source order with duplicates removed. Each returned address is the canonical form of another node: input.name, resource.name, data-source.name, or action.name. Field segments past the node address and @each.X bindings are skipped.

func RootSensitiveOutputs

func RootSensitiveOutputs(
    body syntax.FactoryBody,
    libs map[string]*Library,
    dag *DAG,
) map[string]bool

RootSensitiveOutputs reports root output names whose values must be masked.

func SameEntryRef

func SameEntryRef(a, b EntryRef) bool

func ScopeRef

func ScopeRef(ref, callSite string) string

scopeRef rewrites a reference into a composite internal address. `resource.inner` under call site `resource.outer` becomes `resource.outer/resource.inner`; every segment keeps its own kind root, so resource, data-source, and action refs all join the same way. Input refs and unsupported kinds pass through unchanged so toposort skips them. An empty callSite means the ref is already in its target scope (a top-level boundary's body refs, or a no-op when walking up past the outermost scope) and the ref returns unchanged.

func SealPlan

func SealPlan(p *Plan, enc encrypt.Encrypter) ([]byte, error)

SealPlan encodes p and seals the body in the shared state.Envelope, ready for atomic write. The envelope records the encrypter's own description, whether the operator wrote an encryption block or the resolver chose a default.

func SplitInstanceAddress

func SplitInstanceAddress(addr string) (template, key string)

SplitInstanceAddress separates a `\