Formulas are the descriptions of computations that we want to happen.

They talk about inputs, actions, and outputs.

Formulas are the key L1 concept.

Schema

(And remember, any of the types already defined in Wares, Inputs and Outputs will continue to be referred to here — this layer is building upon that one.)

Formulas

The formula type itself is short and sweet:

# Formula describes a single computation.
# What exactly the computation is is defined by the action
# (of which there are several kinds, but typically, it's commands
# which will be evaluated in some kind of hermetic container),
# and the environment the action wil run it is described by the inputs map.
# What data we collect after the action is completed is defined by the outputs.
type Formula struct {
	inputs {SandboxPort:FormulaInput}
	action Action
	outputs {OutputName:GatherDirective}
}

All the fun stuff comes inside the details of the inputs and outputs, and the action.

Inputs and Outputs

Broadly speaking, identifying where an input should land and where an output will be sourced from is done with straightforward-looking strings. That said, there's a few types that help tease apart and label the semantics of those strings, too:

# SandboxPort defines someplace within the sandbox we'll run the action in
# where data can be either put in or pulled out.
type SandboxPort union {
	| SandboxPath "/"
	| VariableName "$" # REVIEW: maybe call this SandboxVar for some consistency?
} representation stringprefix

# SandboxPath is one of the members of the SandboxPort sum type.
# It's a unix-like path, e.g. something like "foo/bar/baz".
#
# (Despite not beginning with a slash, it's interpreted as an absolute path,
# because the leading slash was stripped by SandboxPort union parse step.)
type SandboxPath string

# VariableName is used to describe a variable (as contrasted with a path).
# When the action is a one of the unixy-container actions,
# these will correspond to environment variables.
#
# Note that though VariableName is syntactically accepted in output declarations,
# it's not guaranteed to be supported by all actions.
#
# Mapping a VariableName to any kind of input other than a literal is strange
# and currently undefined.
type VariableName string

Input data can be declared in a couple of forms:

type FormulaInput union {
	FormulaInputSimple string
	FormulaInputComplex map
} representation kinded

# FIXME revisit name, this happens to also be the RunRecord.results value type!
#  ... except for the mount part, which would make no sense there.  Meh.
type FormulaInputSimple union {
	| WareID  "ware:"     # this is most of the time!
	| Mount   "mount:"    # not hermetic!  we'll warn about the use of these.
	| Literal "literal:"  # a fun escape valve, isn't it.
} representation stringprefix

type FormulaInputComplex struct {
	basis FormulaInputSimple
	filters FilterMap
}

TODO: is some weird composition of "literal:" and a FilterMap going to be sufficient to describe how to make an empty directory? If not, we may need to add another thing to the FormulaInputSimple union for that.