api
import "github.com/umbralcalc/stochadex/pkg/api"Package api is the configuration tier: it turns one YAML document into a running simulation. Everything the engine can do — the forward model, how its partitions are wired, how many seeded members to run, where observations come from, where results go, and the inference, aggregation or optimisation layered on top — is expressible here as data, so a whole run becomes a single artifact that can be versioned, diffed and executed by a prebuilt binary with no Go toolchain present.
How a component is named
Every position in a config that holds a framework component is a data spec — a mapping selecting a registered name, e.g. iteration: {type: wiener_process} or timestep_function: {type: constant, stepsize: 1.0}, resolved at load time by this package’s registries. There is no Go-expression spelling: the whole document is data, so LoadApiRunConfigFromYaml resolves it and RunWithParsedArgs runs it in-process with no Go toolchain. A component given as a scalar Go string is rejected at load.
A partition’s bespoke maths is data too: an expressions: entry (ExpressionConfig, inlining general.ExpressionIteration) states the per-step update as expressions. The registries are for the framework’s own catalogue; the expressions DSL is for a model’s arithmetic. Genuinely novel algorithmic iterations that are neither in the catalogue nor expressible in the DSL belong in a downstream repo that embeds the engine as a Go library (Settings + Implementations), not in a config.
The config surface
main: partitions and the simulation block (output condition and function,
termination condition, timestep function) — see RunConfig.
embedded: named sub-runs, each a whole RunConfig (EmbeddedRunConfig). A main-run
partition whose name matches one is replaced by an embedded simulation
iteration wired to it, which is how a simulation nests inside a partition.
run: execution mode — batch, ensemble (seeds, concurrency) or serve (websocket,
pace_ms; see serve.go) (RunModeConfig).
data: a StateTimeStorage, produced either by a sub-simulation or by a pre-recorded
source (DataSource: csv, json_log, postgres, plus registered ones).
macros: each entry expands one pkg/macros constructor into a set of partitions over
that storage, or runs live with no data: block at all.Where the registries live
registry.go data-only iterations — a name maps to a constructed type, params
carry the rest.
registry_compose.go composable iterations, whose interface-typed fields (kernel,
likelihood, jump distribution, prior, nested iteration, named
function) are themselves specs, resolved recursively. The
"expression" builder here makes the whole expressions DSL usable
as an inline iteration spec, so maths can appear anywhere an
iteration is expected — inside a macro's window, or an embedded run.
macros*.go the macro tier: decodes typed spec structs straight from YAML and
calls the matching pkg/macros constructor. One file per family
(aggregation, inference, smc, optimisation, stats, data, mcts).
registry_environment.go
agents.Environment implementations for the mcts_self_play macro.
Unlike the registries above this one is empty by default and filled
by downstream modules calling RegisterEnvironment: decision rules
are not part of the framework catalogue and have no data spelling,
so the engine passes an env: spec through to its registered builder
without interpreting it. The tictactoe fixture is the exception the
engine ships, so the path stays covered end-to-end in CI.Staying honest, and staying lean
Two drift tests guard the iteration registry (registry_test.go and registry_coverage_test.go): every registered name must construct the type it claims, and a go/ast scan requires every Iterate-implementing type in the candidate packages to be either registered or listed in excludedIterations with a reason. A newly-added iteration therefore fails CI until it is classified, which is what stops the registry silently lagging the framework.
Imports drive go.mod, so components with heavy dependencies are not named here directly. RegisterDataSource (and simulator.RegisterComponent for sinks) lets a package layered above this one contribute a source or output spelling without the engine depending on it; the Arrow, S3 and DuckDB spellings are registered this way by cmd/stochadex. An unknown key reports the spellings the running binary actually has.
Pre\-flight
CheckForDeadlock runs before any batch or ensemble simulation. Within-step wiring (params_from_upstream) that forms a dependency cycle would otherwise surface as an opaque runtime “all goroutines are asleep” with no indication of which partitions are at fault; the check names them and says how to break the cycle. It runs no simulation. See pkg/graph.
Scope
Inference as forward simulation — a posterior stepped as a partition — is in scope, which is why posterior_estimation and the other inference macros live here. Inference against real data is the data: resource, which a downstream repo supplies. The decision layer stays in Go on purpose: an agents.Environment is arbitrary game rules, not representable as data.
Index
- Constants
- Variables
- func Check(config *ApiRunConfig) error
- func CheckForDeadlock(generator *simulator.ConfigGenerator) error
- func Execute(args []string) error
- func ExitCode(err error) int
- func ExpandToYAML(config *ApiRunConfig) ([]byte, error)
- func LoadFormat(format string, fields map[string]interface{}) (*simulator.StateTimeStorage, error)
- func LogRunProvenance(w io.Writer)
- func NewWebsocketHandler(build func() *simulator.ConfigGenerator, stepDelay time.Duration, allowedOrigins []string) http.Handler
- func RegisterDataSource(name string, build func(fields map[string]interface{}) (*simulator.StateTimeStorage, error))
- func RegisterEnvironment(typeName string, build EnvironmentBuilder)
- func RegisterIteration(typeName string, build func(simulator.ComponentSpec) (simulator.Iteration, error))
- func RegisterSourceFingerprint(name string, fingerprint func(fields map[string]interface{}) (string, error))
- func RegisterStreamTransport(name string, transport StreamTransport)
- func RegisteredEnvironments() []string
- func ResolveIteration(spec simulator.ComponentSpec) (simulator.Iteration, error)
- func Run(config *ApiRunConfig, socket *SocketConfig)
- func RunEnsembleToStorage(config *ApiRunConfig) ([]simulator.EnsembleRun, error)
- func RunMacros(config *ApiRunConfig) (*simulator.StateTimeStorage, error)
- func RunWithParsedArgs(args ParsedArgs)
- func StepAndServeWebsocket(build func() *simulator.ConfigGenerator, stepDelay time.Duration, handle string, address string, allowedOrigins []string)
- type ApiRunConfig
- func Expand(config *ApiRunConfig) (*ApiRunConfig, error)
- func LoadApiRunConfigFromYaml(path string, options …LoadOption) *ApiRunConfig
- func LoadConfig(path string, options …LoadOption) (*ApiRunConfig, error)
- func (a *ApiRunConfig) Deprecations() []string
- func (a *ApiRunConfig) GetConfigGenerator() *simulator.ConfigGenerator
- type ConnectionStreamConfig
- type DataConfig
- type DataSource
- type EmbeddedRunConfig
- type EnvironmentBuilder
- type Error
- type ErrorKind
- type ExpressionConfig
- type FileInputConfig
- type IOManifest
- type InlineSource
- type InputConfig
- type LoadOption
- type MCTSEnvironment
- type MCTSEnvironmentSpec
- type MacroConfig
- type ManifestClock
- type ManifestColumns
- type ManifestEmbedded
- type ManifestInput
- type ManifestOutput
- type ManifestRun
- type OutputViewConfig
- type ParsedArgs
- type Provenance
- type ProvenanceBuild
- type ProvenanceConfig
- type ProvenanceInput
- type RunConfig
- type RunModeConfig
- type RunOption
- type RunResult
- type SocketConfig
- type StreamConfig
- type StreamSource
- type StreamTransport
- type WebsocketServeConfig
- type WebsocketStreamConfig
Constants
Exit codes, following BSD sysexits.h so an orchestrator can map them without stochadex-specific knowledge. A panic the engine cannot intercept (one raised inside a partition’s worker goroutine) still exits with Go’s own status 2, which callers should treat like ExitRuntime.
const (
ExitOK = 0
ExitUsage = 64 // EX_USAGE
ExitData = 65 // EX_DATAERR
ExitRuntime = 70 // EX_SOFTWARE
ExitUnavailable = 75 // EX_TEMPFAIL: the one class worth retrying
ExitConfig = 78 // EX_CONFIG
)Variables
BuildVersion and BuildFeatures describe the executable orchestrating a run. They default to the base engine’s view — “dev”, no optional features — and are overwritten by a CLI’s main package before RunWithParsedArgs is called. cmd/stochadex sets them from its own -ldflags version stamp and its compiled-in feature list, so a provenance line reports exactly the binary that ran rather than a generic default.
var (
BuildVersion = "dev"
BuildFeatures []string
)BuildRevision is the git commit a build was stamped with via -ldflags, for builds that cannot read it from the embedded Go build info. The OCI image is exactly this case: its build context excludes .git (see .dockerignore), so the toolchain has no VCS to read and the release workflow passes the commit in explicitly instead. When set it wins over the embedded build info; when empty the build info is used, which is how the binary releases (built with .git present) report their revision.
var BuildRevision = ""func Check
func Check(config *ApiRunConfig) errorCheck validates a loaded config as far as it can without running it or reading its inputs: everything LoadConfig checks, plus the run mode’s preconditions, the partitions’ wiring, the deadlock pre-flight, and each iteration’s Configure. Only what needs an input’s contents is left to the run: that the input has the partitions the config reads, and their widths where the config does not declare them. A macros: config’s expansion also needs its inputs’ contents, so Check validates only its context, until macros expand from the config alone (PLAN.md Phase 2).
Check builds fresh instances to check, so config is left as it was. Failures are ErrConfig.
func CheckForDeadlock
func CheckForDeadlock(generator *simulator.ConfigGenerator) errorCheckForDeadlock reports whether the generator’s within-step wiring (params_from_upstream) contains a dependency cycle that would deadlock the channel-based execution strategies (the default and persistent-worker strategies), returning a descriptive error naming the partitions in each cycle. It runs no simulation. Without this pre-flight check such a cycle surfaces only as an opaque runtime “all goroutines are asleep - deadlock!” with no indication of which partitions are at fault. See pkg/graph.
func Execute
func Execute(args []string) errorExecute is the CLI’s whole run: parse args (os.Args form), load the config and optional socket config, and run. It never exits or panics on a failure it can intercept; it returns an *Error whose kind ExitCode maps to the process exit status. Unlike ArgParse / LoadSocketConfigFromYaml, it writes nothing to stdout of its own, so stdout carries only the run’s output.
func ExitCode
func ExitCode(err error) intExitCode maps err to the CLI exit code for its kind (ExitOK for nil).
func ExpandToYAML
func ExpandToYAML(config *ApiRunConfig) ([]byte, error)ExpandToYAML writes a macros: config out in the core language: one run, as YAML a person could have written. Every macro expands; a config whose macros cannot run as one run with one clock (see calibrationSplit) is an error saying why. Calibrate, then plan becomes a run: input, named calibration, holding the inputs and the macros before the planner, which the planner’s run reads.
func LoadFormat
func LoadFormat(format string, fields map[string]interface{}) (*simulator.StateTimeStorage, error)LoadFormat loads storage for a single named source format from raw fields. It exists so a transport registered above this package — the S3 source, which fetches an object and then needs it parsed — can reuse the local loaders verbatim instead of re-implementing their field handling (a CSV’s time_column/state_columns/skip_header, and so on).
The fields are round-tripped through YAML into the same typed structs the config path uses, so a transported source validates exactly like a local one.
func LogRunProvenance
func LogRunProvenance(w io.Writer)LogRunProvenance writes a single machine-parseable provenance line to w at the start of a run. It is deliberately sent to stderr, never stdout, so it never corrupts a data output (StdoutOutputFunction writes result rows to stdout); in a containerised run — the image’s whole reason for being — the job log that captures stderr is the durable record a result is reproduced against. The line is space-separated key=value pairs so it survives log aggregation and greps cleanly:
stochadex-run version=v0.7.0 os=linux arch=arm64 revision=d44bcd8… features=arrow,cblas,duckdb,postgres,s3 image=sha256:abc…revision and dirty come from the Go build info the toolchain embeds automatically (buildvcs, on by default); image= is present only when STOCHADEX_IMAGE_DIGEST is set. A result is only reproducible if you know which build produced it, and this line is that binding for the CLI/image surface.
func NewWebsocketHandler
func NewWebsocketHandler(build func() *simulator.ConfigGenerator, stepDelay time.Duration, allowedOrigins []string) http.HandlerNewWebsocketHandler returns the http.Handler behind StepAndServeWebsocket: each connection gets its own simulation, built fresh by build, stepped under the configured execution strategy and streamed until it terminates or the client disconnects.
Building per connection is load-bearing. A ConfigGenerator hands out the same iteration instances on every GenerateConfigs call, so reusing one generator would have concurrent clients stepping one shared, mutable model.
func RegisterDataSource
func RegisterDataSource(name string, build func(fields map[string]interface{}) (*simulator.StateTimeStorage, error))RegisterDataSource adds a data: source spelling that this package cannot depend on directly. It mirrors simulator.RegisterComponent: the engine stays lean, and the distributed CLI contributes the sources whose dependencies it alone carries.
func RegisterEnvironment
func RegisterEnvironment(typeName string, build EnvironmentBuilder)RegisterEnvironment adds an environment spelling, usable as the mcts_* iterations’ environment: type and as the mcts_self_play macro’s env: type. Call it from an init function in the module that owns the environment; the engine only sees it if the binary links that module, so a downstream ships its own CLI (as cmd/stochadex does for the ONNX partition).
Panics on a duplicate name, so two modules cannot silently claim one spelling, and on “simulation”, which is the engine’s own.
func RegisterIteration
func RegisterIteration(typeName string, build func(simulator.ComponentSpec) (simulator.Iteration, error))RegisterIteration registers an iteration builder for a {type: …} spelling that lives downstream of this package. Call it from an init(); it panics on a duplicate so two packages cannot silently claim one name. The builder receives the whole ComponentSpec (Type plus Fields) and is responsible for strict field validation, just like the core builders.
func RegisterSourceFingerprint
func RegisterSourceFingerprint(name string, fingerprint func(fields map[string]interface{}) (string, error))RegisterSourceFingerprint tells provenance how to fingerprint a source registered with RegisterDataSource: for an object store, say, its object version rather than its bytes. A registered source without one is fingerprinted by the file at its path field, and is uncacheable without one.
func RegisterStreamTransport
func RegisterStreamTransport(name string, transport StreamTransport)RegisterStreamTransport makes a stream transport available to configs under name, as stream: {name: {…fields}}.
func RegisteredEnvironments
func RegisteredEnvironments() []stringRegisteredEnvironments returns the registered spellings in sorted order, for error messages and for a downstream to check what its binary has linked.
func ResolveIteration
func ResolveIteration(spec simulator.ComponentSpec) (simulator.Iteration, error)ResolveIteration builds a simulator.Iteration from a data-spec ComponentSpec, as a run of its own.
func Run
func Run(config *ApiRunConfig, socket *SocketConfig)Run executes the configured simulation under the mode named by the config’s run: block. The default (empty or “batch”) runs once to completion offline; “ensemble” runs one seeded member per seed concurrently, each writing its own views; “serve” serves a websocket, one fresh run per connection, until the server fails. A macros: run’s result is replayed through the views. Every mode writes through the config’s outputs: views, which hold the shorthand output pair or, when no output is declared, every step to stdout.
An active socket config is a deprecated alias for run: {mode: serve}: it switches a batch config to serving with the socket’s address, handle, origins and delay.
A failure exits the process; a panic raised while running propagates. Use Execute (as the CLI does) for classified errors and exit codes instead.
func RunEnsembleToStorage
func RunEnsembleToStorage(config *ApiRunConfig) ([]simulator.EnsembleRun, error)RunEnsembleToStorage runs the config’s ensemble and returns each member’s recorded storage, index-aligned to run.seeds, whatever run.mode says.
The ensemble mechanism rebuilds each member by re-loading the source file for fresh, non-shared iteration instances, so: the config must have been loaded from a file; embedded runs are unsupported; every main partition must resolve a data iteration; and run.seeds must be non-empty.
Deprecated: use RunToStorage with run: {mode: ensemble}, which returns the same members in RunResult.Members.
func RunMacros
func RunMacros(config *ApiRunConfig) (*simulator.StateTimeStorage, error)RunMacros expands and runs a config’s macros: tier and returns the resulting storage.
Deprecated: use RunToStorage, which runs a macros: config the same way and returns its storage in RunResult.Storage.
func RunWithParsedArgs
func RunWithParsedArgs(args ParsedArgs)RunWithParsedArgs runs the configured simulation. The whole config is data (data-spec partitions and simulation, or expressions:, plus optional data:/macros: tiers), so it is resolved and run in-process with no Go toolchain.
func StepAndServeWebsocket
func StepAndServeWebsocket(build func() *simulator.ConfigGenerator, stepDelay time.Duration, handle string, address string, allowedOrigins []string)StepAndServeWebsocket steps a simulation and streams state updates over a websocket using simulator.WebsocketOutputFunction.
Usage hints:
- The HTTP server mounts the websocket at handle and listens on address.
- stepDelay controls the delay between steps in milliseconds.
- build is called once per connection and must return a generator with fresh iteration instances, so concurrent clients never share state.
- allowedOrigins extends the default origin policy (see websocketOriginCheck).
type ApiRunConfig
ApiRunConfig is the concrete, YAML-loadable configuration for an API run: a main RunConfig, optional embedded runs, and an optional run-mode selector.
type ApiRunConfig struct {
Main RunConfig `yaml:"main"`
Embedded []EmbeddedRunConfig `yaml:"embedded,omitempty"`
Run RunModeConfig `yaml:"run,omitempty"`
// Data is the optional data: tier — a sub-simulation run to produce storage
// for the macros: tier to analyse.
Data *DataConfig `yaml:"data,omitempty"`
// Macros is the optional macros: tier — partition-set-producing analysis
// functions expanded against Data's storage.
Macros []MacroConfig `yaml:"macros,omitempty"`
// Outputs are the run's output views: each a named sink gated by its own
// condition, all fed from the one run. Mutually exclusive with
// main.simulation's output_condition / output_function, which are shorthand
// for a single unnamed view.
Outputs []OutputViewConfig `yaml:"outputs,omitempty"`
// Inputs are named, read-only storages read when a run starts and replayed
// into main: partitions with {type: from_input} (see inputs.go).
Inputs map[string]InputConfig `yaml:"inputs,omitempty"`
// contains filtered or unexported fields
}func Expand
func Expand(config *ApiRunConfig) (*ApiRunConfig, error)Expand writes a macros: config out in the core language (ExpandToYAML) and loads the result, as a config the single runtime runs like any other.
func LoadApiRunConfigFromYaml
func LoadApiRunConfigFromYaml(path string, options ...LoadOption) *ApiRunConfigLoadApiRunConfigFromYaml loads simulation configuration from a YAML file.
The whole config is data: partition iterations are {type: …} specs or expressions:, and every simulation: component is a {type: …} spec. It resolves and runs in-process — no code generation, no Go toolchain.
Parameters:
- path: Path to the YAML configuration file (must exist and be readable)
Returns:
- *ApiRunConfig: Loaded and initialized configuration ready for execution
YAML File Format:
main:
partitions:
- name: "process1"
iteration: {type: wiener_process}
params:
variances: [0.1, 0.2]
init_state_values: [0.0, 0.0]
state_history_depth: 10
seed: 42
simulation:
output_condition: {type: every_step}
output_function: {type: stdout}
termination_condition: {type: number_of_steps, max_steps: 1000}
timestep_function: {type: constant, stepsize: 0.01}
init_time_value: 0.0
embedded:
- name: "sub_simulation"
partitions: [...]
simulation: [...]Error Handling:
- Panics on file read errors (file not found, permission denied)
- Panics on YAML parsing errors (malformed YAML, type mismatches)
- Panics on data-spec resolution errors (unknown type, bad field)
func LoadConfig
func LoadConfig(path string, options ...LoadOption) (*ApiRunConfig, error)LoadConfig loads and resolves a config like LoadApiRunConfigFromYaml, but returns a failure instead of panicking. Every failure is an ErrConfig *Error: an unreadable file, invalid YAML, a key nothing reads, an unknown type or field, or a partition with no iteration.
options apply per-invocation overrides before anything is checked: WithSet replaces a value by its path, and ${VAR} placeholders in the file are filled from the environment (or WithEnv). See overrides.go.
func (*ApiRunConfig) Deprecations
func (a *ApiRunConfig) Deprecations() []stringDeprecations are notices for the deprecated forms the config uses, each naming its replacement.
func (*ApiRunConfig) GetConfigGenerator
func (a *ApiRunConfig) GetConfigGenerator() *simulator.ConfigGeneratorGetConfigGenerator returns a ConfigGenerator for the main run. Any partition whose name matches an embedded run is replaced by an embedded simulation iteration wired to that embedded run.
type ConnectionStreamConfig
ConnectionStreamConfig selects a served client as a stream. It has no fields: spell it connection: {}.
type ConnectionStreamConfig struct{}type DataConfig
DataConfig is the data: tier: it produces the StateTimeStorage that macros analyse, either by running a sub-simulation (Partitions run for Steps) or by loading a file (Source). Sub-simulation partitions carry data-spec iterations (or expressions), like any other run.
type DataConfig struct {
// Source loads storage from a file. When set, the sub-simulation fields below
// are ignored.
Source *DataSource `yaml:"source,omitempty"`
Partitions []simulator.PartitionConfig `yaml:"partitions,omitempty"`
Expressions []ExpressionConfig `yaml:"expressions,omitempty"`
Steps int `yaml:"steps,omitempty"`
Timestep float64 `yaml:"timestep,omitempty"`
InitTime float64 `yaml:"init_time,omitempty"`
}type DataSource
DataSource is the data: tier’s optional pre-recorded source: instead of running a sub-simulation, storage is loaded from a file or a database. Exactly one field is set.
type DataSource struct {
Csv *csvSource `yaml:"csv,omitempty"`
JsonLog *jsonLogSource `yaml:"json_log,omitempty"`
Postgres *postgresSource `yaml:"postgres,omitempty"`
// Inline carries the data in the config itself.
Inline *InlineSource `yaml:"inline,omitempty"`
// Extra captures any source key not named above, so a package layered on top of
// api can contribute one through RegisterDataSource without this struct (and
// therefore the engine's go.mod) having to know about its dependencies. The Arrow
// source is registered this way by the distributed CLI, because arrow-go lives in
// a separate opt-in module.
Extra map[string]map[string]interface{} `yaml:",inline"`
}type EmbeddedRunConfig
EmbeddedRunConfig names and embeds an additional RunConfig that can be wired into a partition in the main run.
type EmbeddedRunConfig struct {
Name string `yaml:"name"`
Run RunConfig `yaml:",inline"`
}type EnvironmentBuilder
EnvironmentBuilder constructs an environment from its data spec, whose fields only the builder parses.
type EnvironmentBuilder func(spec simulator.ComponentSpec) (MCTSEnvironment, error)type Error
Error is a failure with its ErrorKind. It wraps the underlying error, so errors.Is / errors.As see through it.
type Error struct {
Kind ErrorKind
Err error
}func (*Error) Error
func (e *Error) Error() stringfunc (*Error) Unwrap
func (e *Error) Unwrap() errortype ErrorKind
ErrorKind classifies why a run failed, so a caller — an orchestrator reading the CLI’s exit code, or Go code inspecting an error — can decide whether retrying could help. Only ErrUnavailable is worth retrying.
type ErrorKind intconst (
// ErrConfig: the config is invalid (syntax, unknown key or type, wiring,
// deadlock, run mode). Fix the config; retrying cannot help.
ErrConfig ErrorKind = iota + 1
// ErrUsage: the command line was wrong.
ErrUsage
// ErrData: an input was reachable but its contents could not be used.
ErrData
// ErrUnavailable: an input or output resource could not be reached — a
// missing input file, a refused connection. Retrying later may succeed.
ErrUnavailable
// ErrRuntime: the simulation itself failed while running.
ErrRuntime
)func KindOf
func KindOf(err error) ErrorKindKindOf reports the ErrorKind of err: the kind it was classified with, or ErrRuntime for an unclassified failure. It returns 0 for a nil error.
type ExpressionConfig
ExpressionConfig binds a declarative expression specification to a partition by name, so that a partition’s whole update can be written as data in the config file.
An expression specification is just data: it is loaded straight from the YAML and evaluated at run time, so a config using only expressions needs no compilation at all. This is what lets a simulation be specified by something that does not write Go.
A partition named here may omit its iteration field, exactly as a partition backed by an embedded run may. The specification is inlined, so its keys are those of general.ExpressionIteration:
expressions:
- partition: battery
fields:
- {name: soc}
- {name: actual_dispatch}
bindings:
- {name: dispatch, expr: "clamp(dispatch_mw, -power_rating_mw, power_rating_mw)"}
outputs: ["clamp(soc + dispatch * dt, 0, energy_capacity_mwh)", "dispatch"]type ExpressionConfig struct {
Partition string `yaml:"partition"`
general.ExpressionIteration `yaml:",inline"`
}type FileInputConfig
FileInputConfig is a file an iteration reads.
type FileInputConfig struct {
Path string `yaml:"path"`
}type IOManifest
IOManifest describes what a run of a config reads and writes, without running it. Its JSON form is what `stochadex inspect --io` prints.
Locations are given as the config writes them: a relative path is relative to the directory the run starts in. Nothing secret is reported: a sink’s or source’s fields are never copied, only its location, and the values of ${VAR} placeholders are withheld.
type IOManifest struct {
// Config is the path the config was loaded from.
Config string `json:"config"`
// Overrides are the --set overrides applied, as written; Variables the
// ${VAR} placeholders filled, by name.
Overrides []string `json:"overrides,omitempty"`
Variables []string `json:"variables,omitempty"`
Run ManifestRun `json:"run"`
Clock *ManifestClock `json:"clock,omitempty"`
Inputs []ManifestInput `json:"inputs"`
// Outputs are every place the run writes its results: the outputs: views
// (including the shorthand and default view) and each stream input's
// record file. Debug logs are listed apart, in Debug.
Outputs []ManifestOutput `json:"outputs"`
// Embedded describes each embedded run as the outer run sees it: a black
// box whose host partition's row, each outer step, is its inner partitions'
// final states concatenated in Columns' order.
Embedded []ManifestEmbedded `json:"embedded,omitempty"`
// Deprecations are notices for the deprecated forms the config uses, each
// naming its replacement.
Deprecations []string `json:"deprecations,omitempty"`
// Debug lists the logs a run writes only because its config asks for an
// embedded run's inner detail: every inner step of every outer step. They
// are for debugging, not results (rule 14), so provenance and
// --skip-if-unchanged ignore them.
Debug []ManifestOutput `json:"debug,omitempty"`
}func Manifest
func Manifest(config *ApiRunConfig) *IOManifestManifest describes what config reads and writes. It reads nothing.
type InlineSource
InlineSource is data carried in the config itself (source: {inline: …}): a time axis, and each partition’s rows, one row per time. A source with only times can drive a clock (timestep_function: {type: from_input}).
type InlineSource struct {
Times []float64 `yaml:"times"`
Partitions map[string][][]float64 `yaml:"partitions,omitempty"`
}type InputConfig
InputConfig is one entry of inputs:. Exactly one of Source, Simulation, Run, Stream and File is set.
type InputConfig struct {
// Source loads the input from a file or database (the data.source spellings).
Source *DataSource `yaml:"source,omitempty"`
// Simulation produces the input by running a sub-simulation first.
Simulation *DataConfig `yaml:"simulation,omitempty"`
// Run produces the input by running a config of its own first: one with
// inputs:, main: and embedded:, or macros:, which runs once (batch). Its
// recorded rows are the input's, as RunToStorage returns them; its own
// outputs are not written.
Run *ApiRunConfig `yaml:"run,omitempty"`
// Stream reads the input live, from outside the run, while it runs (see
// streams.go). Only params_from_input reads a stream input.
Stream *StreamConfig `yaml:"stream,omitempty"`
// File is a file an iteration reads, such as a model, named by an
// iteration field {input: NAME} (see file_inputs.go).
File *FileInputConfig `yaml:"file,omitempty"`
// Decode is how a stream's messages are read: "json" (the default), each
// message a json_log entry or a JSON array of them; or
// "protobuf_action_state", each message a simulator.ActionState.
Decode string `yaml:"decode,omitempty"`
// OnEmpty is what a stream input gives a step that no new message has
// reached: "hold_last" (the default, and for now the only choice) holds the
// last value.
OnEmpty string `yaml:"on_empty,omitempty"`
// Record writes the values a stream input gave each step to this json_log
// path, so the run can be replayed from it as a source input. Under
// run: {mode: serve} it must contain {connection}, as output views must.
Record string `yaml:"record,omitempty"`
}type LoadOption
LoadOption configures LoadConfig.
type LoadOption func(*loadOptions)func WithEnv
func WithEnv(lookup func(string) (string, bool)) LoadOptionWithEnv fills ${VAR} placeholders from lookup instead of the process environment; lookup reports whether the variable is set, as os.LookupEnv.
func WithSet
func WithSet(path, value string) LoadOptionWithSet replaces the value at path with value, read as YAML. path joins mapping keys with dots and selects a list entry by name, as in main.partitions[name=w].params.rate; it must already exist in the config.
type MCTSEnvironment
MCTSEnvironment is an environment the MCTS iterations, and mcts_self_play, search. Build one with NewMCTSEnvironment.
type MCTSEnvironment interface {
// contains filtered or unexported methods
}func NewMCTSEnvironment
func NewMCTSEnvironment[S any, A any](spec MCTSEnvironmentSpec[S, A]) (MCTSEnvironment, error)NewMCTSEnvironment makes an environment a component the MCTS iterations and mcts_self_play can search. Chance nodes, which average each action over sampled successors, are available only when Env is an agents.StochasticEnvironment; for deterministic rules the search commits to the one successor, which is exactly right.
func ResolveEnvironment
func ResolveEnvironment(spec simulator.ComponentSpec) (MCTSEnvironment, error)ResolveEnvironment builds the registered environment a spec names.
type MCTSEnvironmentSpec
MCTSEnvironmentSpec is an environment for its own state and action types, with what the MCTS iterations need to know about it.
type MCTSEnvironmentSpec[S any, A any] struct {
// Env is the decision rules.
Env agents.Environment[S, A]
// Rollout plays out a leaf; nil plays uniformly at random. Progress
// optionally scores a position for a rollout cut short.
Rollout agents.MCTSRolloutFn[S, A]
Progress func(s S, player int) (float64, bool)
// InitState is where mcts_self_play starts. Encoder and Decoder are its
// codec into a partition's row, Decoder round-tripping Encoder.
InitState S
Encoder func(S) []float64
Decoder func([]float64) (S, error)
// MaxLegalActions bounds the legal actions any state has, StateWidth is
// the encoded state's length, and Players the number of players. They
// are the environment's own shape, so never config's to state: a
// mismatch is a silently misshapen row rather than a loud error.
MaxLegalActions, StateWidth, Players int
// SearchDepth bounds the tree and the rollouts when the config sets no
// limit; zero leaves the agents defaults.
SearchDepth int
// SimsPerPly is mcts_self_play's sims_per_ply when the config sets none.
SimsPerPly int
}type MacroConfig
MacroConfig is one entry in the macros: tier. It decodes its `type` and then the whole entry into that type’s typed spec, so field values keep their YAML types (see the package note on the `y`->true coercion).
type MacroConfig struct {
Type string
Spec macroSpec
}func (*MacroConfig) UnmarshalYAML
func (m *MacroConfig) UnmarshalYAML(unmarshal func(interface{}) error) errorUnmarshalYAML reads the macro type, then decodes the entry into the matching typed spec. The type is read via a map (which accepts any keys) so this does not trip the strict dead-key check; the typed spec decode that follows is what validates the remaining keys.
type ManifestClock
ManifestClock is where the main run’s time comes from, and what ends it. An input is named when a clock component reads one.
type ManifestClock struct {
Timestep string `json:"timestep"`
TimestepInput string `json:"timestep_input,omitempty"`
Termination string `json:"termination"`
TerminationInput string `json:"termination_input,omitempty"`
}type ManifestColumns
ManifestColumns are the columns of a host partition’s row that hold one inner partition’s final state: [Offset, Offset+Width).
type ManifestColumns struct {
Partition string `json:"partition"`
Offset int `json:"offset"`
Width int `json:"width"`
}type ManifestEmbedded
ManifestEmbedded is an embedded run’s host partition and its column layout.
type ManifestEmbedded struct {
Partition string `json:"partition"`
Columns []ManifestColumns `json:"columns"`
}type ManifestInput
ManifestInput is one input: what kind it is, where it is, and what reads it.
type ManifestInput struct {
Name string `json:"name"`
// Kind is the source (csv, json_log, postgres, or a registered source such
// as arrow or s3), simulation for an input made by a sub-simulation, or
// stream.
Kind string `json:"kind"`
Location string `json:"location,omitempty"`
// Partitions are the input's partitions the run reads, where the config
// names them; ReadBy says what reads the input, by config path.
Partitions []string `json:"partitions,omitempty"`
ReadBy []string `json:"read_by,omitempty"`
}type ManifestOutput
ManifestOutput is one place a run writes.
type ManifestOutput struct {
Name string `json:"name"`
// DeclaredIn is where the config declares it: outputs, main.simulation
// (the shorthand pair), default (no output declared), an embedded run's
// simulation, or a stream input's record.
DeclaredIn string `json:"declared_in"`
Condition string `json:"condition"`
Sink string `json:"sink"`
// Location is as declared, so under ensemble or serve it may hold
// {member}, {seed} or {connection}. Locations lists an ensemble's, one per
// member, with those filled in.
Location string `json:"location,omitempty"`
Locations []string `json:"locations,omitempty"`
}type ManifestRun
ManifestRun is how many runtimes a config makes, and of what kind.
type ManifestRun struct {
// Mode is batch, ensemble or serve.
Mode string `json:"mode"`
// Runtime is main, or macros for a macros: config, which runs its macros in
// turn against its inputs (until macros expand into the main runtime).
Runtime string `json:"runtime"`
Macros []string `json:"macros,omitempty"`
Seeds []uint64 `json:"seeds,omitempty"`
Concurrency int `json:"concurrency,omitempty"`
Address string `json:"address,omitempty"`
Handle string `json:"handle,omitempty"`
}type OutputViewConfig
OutputViewConfig is one entry of outputs:. Condition defaults to every_step.
type OutputViewConfig struct {
Name string `yaml:"name"`
Condition simulator.ComponentSpec `yaml:"condition,omitempty"`
Function simulator.ComponentSpec `yaml:"function"`
// contains filtered or unexported fields
}type ParsedArgs
ParsedArgs bundles CLI-derived inputs for running the API: the YAML config path, any --set overrides (each path=value), and an optional socket config path.
type ParsedArgs struct {
ConfigFile string
Sets []string
// SeedRange runs one shard of an ensemble: FROM:TO, the seeds FROM to TO
// inclusive, in place of run.seeds (--seed-range).
SeedRange string
// DebugEmbedded writes embedded runs' inner steps to json_logs, each
// NAME=PATH (--debug-embedded).
DebugEmbedded []string
SocketFile string
// Check validates the config and exits without running it (--check).
Check bool
// InspectIO prints the config's I/O manifest instead of running it
// (stochadex inspect --io).
InspectIO bool
// InspectProvenance prints the run's provenance, with its key, instead of
// running it (stochadex inspect --provenance).
InspectProvenance bool
// Provenance writes a provenance sidecar beside each file output
// (--provenance); SkipIfUnchanged skips a run whose outputs already carry
// its key, and implies Provenance (--skip-if-unchanged).
Provenance bool
SkipIfUnchanged bool
}func ArgParse
func ArgParse() ParsedArgsArgParse parses CLI flags into a ParsedArgs.
type Provenance
Provenance describes what produced a run’s outputs.
type Provenance struct {
// Key identifies the run's outputs; it is empty when the run is not
// cacheable, and Uncacheable then says why.
Key string `json:"key,omitempty"`
Uncacheable []string `json:"uncacheable,omitempty"`
Config ProvenanceConfig `json:"config"`
Inputs []ProvenanceInput `json:"inputs"`
Seeds []uint64 `json:"seeds,omitempty"`
Build ProvenanceBuild `json:"build"`
}func ComputeProvenance
func ComputeProvenance(config *ApiRunConfig) (*Provenance, error)ComputeProvenance fingerprints what a run of config would read. It reads every file input and model file once, so a missing input is ErrUnavailable, as it would be for the run.
type ProvenanceBuild
ProvenanceBuild is the build that ran. Version and Revision are what its build process stamped, and identify it; VCSRevision and VCSDirty are Go’s own version-control stamp, recorded for information only.
type ProvenanceBuild struct {
Version string `json:"version"`
Revision string `json:"revision,omitempty"`
VCSRevision string `json:"vcs_revision,omitempty"`
VCSDirty bool `json:"vcs_dirty,omitempty"`
Features []string `json:"features,omitempty"`
OS string `json:"os"`
Arch string `json:"arch"`
Image string `json:"image,omitempty"`
}type ProvenanceConfig
ProvenanceConfig is the config as resolved: its path, the overrides applied, and a digest of the resolved document that ignores comments, layout and key order.
type ProvenanceConfig struct {
Path string `json:"path"`
SHA256 string `json:"sha256"`
Overrides []string `json:"overrides,omitempty"`
Variables []string `json:"variables,omitempty"`
}type ProvenanceInput
ProvenanceInput is one input and the fingerprint of its contents.
type ProvenanceInput struct {
Name string `json:"name"`
Kind string `json:"kind"`
Location string `json:"location,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
}type RunConfig
RunConfig represents a complete simulation run configuration with partitions and simulation settings.
This struct combines partition configurations with simulation control parameters to define a complete simulation run. It serves as the primary configuration structure for YAML-based simulation setup.
Fields:
- Partitions: List of partition configurations defining the simulation state
- Expressions: Declarative iterations bound to partitions by name
- SimulationStrings: The simulation block as loaded (component data specs)
- Simulation: The resolved simulation config (not loaded from YAML directly)
YAML Structure:
partitions:
- name: "process1"
iteration: {type: wiener_process}
params:
variances: [0.1, 0.2]
init_state_values: [0.0, 0.0]
- name: "process2"
iteration: {type: poisson_process}
params:
rates: [0.5, 1.0]
init_state_values: [0.0, 0.0]Related Types:
- See simulator.PartitionConfig for partition configuration details
- See simulator.SimulationConfig for simulation control parameters
- See ApiRunConfig for API-level configuration with embedded runs
- See ExpressionConfig for supplying a partition’s iteration as data instead of Go
type RunConfig struct {
Partitions []simulator.PartitionConfig `yaml:"partitions"`
// Expressions declaratively supply the iteration for the partitions they name.
Expressions []ExpressionConfig `yaml:"expressions,omitempty"`
// SimulationStrings holds the simulation block as loaded (component fields are
// {type: ...} data specs). It is resolved into Simulation at load time.
SimulationStrings simulator.SimulationConfigStrings `yaml:"simulation"`
// Simulation is the resolved simulation config used to build the generator.
Simulation simulator.SimulationConfig `yaml:"-"`
}func (*RunConfig) GetConfigGenerator
func (r *RunConfig) GetConfigGenerator() *simulator.ConfigGeneratorGetConfigGenerator constructs a ConfigGenerator preloaded with the run’s SimulationConfig and Partitions, and gives any partition named by an Expressions entry a declarative ExpressionIteration built from that entry.
type RunModeConfig
RunModeConfig selects what a run *does* with the assembled simulation — the one thing that is not a partition and that the partition tiers cannot express.
Modes:
- “” or “batch”: run once to completion. This is the default.
- “ensemble”: run one member per seed concurrently, varying the global seed, via simulator.RunSeededEnsemble. Each member is rebuilt by re-loading the source file to get fresh, non-shared iteration instances.
- “serve”: serve a websocket; each connection gets its own fresh run of the model, streamed to it step by step (see serve.go).
type RunModeConfig struct {
Mode string `yaml:"mode,omitempty"`
// Seeds are the per-member global seeds for ensemble mode (one member each).
Seeds []uint64 `yaml:"seeds,omitempty"`
// Concurrency bounds how many ensemble members run at once; <= 0 defaults to
// GOMAXPROCS.
Concurrency int `yaml:"concurrency,omitempty"`
// Websocket is where serve mode listens.
Websocket *WebsocketServeConfig `yaml:"websocket,omitempty"`
// PaceMs is a delay between steps, in milliseconds, so a served client, or
// someone at the keyboard, sees the run at a watchable rate. It paces a
// served run and a batch run from the CLI; RunWith and RunToStorage, which
// return a run's results, run unpaced.
PaceMs uint64 `yaml:"pace_ms,omitempty"`
}type RunOption
RunOption configures RunWith.
type RunOption func(*runOptions)func CaptureView
func CaptureView(name string, condition simulator.OutputCondition) RunOptionCaptureView attaches an in-memory view to a run: the rows condition selects (every step when nil) come back in RunResult.Views[name].
func WithConfigOutputs
func WithConfigOutputs() RunOptionWithConfigOutputs also runs the config’s own outputs — its outputs: views or output_function, and any nested run’s sinks — alongside the captured views. Without it they are suppressed: nothing is written outside the process.
type RunResult
RunResult is what one run of a config produced. Storage holds a batch run’s default view (RunToStorage) or a macros run’s result; Views holds the in-memory views a caller attached with CaptureView, by name; Members holds an ensemble’s members, index-aligned to run.seeds.
type RunResult struct {
Storage *simulator.StateTimeStorage
Views map[string]*simulator.StateTimeStorage
Members []simulator.EnsembleRun
}func RunToStorage
func RunToStorage(config *ApiRunConfig) (*RunResult, error)RunToStorage runs a config and returns what it produced instead of emitting it: RunWith with one in-memory view that records what the config’s own output_condition selects (every step under outputs:), returned as RunResult.Storage, and the config’s outputs — nested runs’ sinks included — suppressed. A macros: config returns its result; an ensemble its members. Every partition is registered in the storage; one the condition never selects is present with no rows. The caller’s config is not modified. Every failure is returned as an error rather than exiting.
Serving a websocket is not a storage-returning run and is only reachable through Run.
func RunWith
func RunWith(config *ApiRunConfig, options ...RunOption) (*RunResult, error)RunWith runs a config, returning the in-memory views the caller attached with CaptureView. By default the config’s own outputs are suppressed — including the sinks of nested (embedded) runs — so the run has no side effects outside the process; WithConfigOutputs writes them as well. The caller’s config is not modified. Every failure is returned as an error, never an exit: a partition that panics, under any execution strategy, fails the run with an ErrRuntime naming it.
A macros: config’s result is also returned as RunResult.Storage, and each captured view receives it replayed as a live run would output it. An ensemble returns RunResult.Members; with WithConfigOutputs each member also writes its own outputs: views ({member} / {seed} substituted). Captured views do not yet apply to ensembles and are rejected.
type SocketConfig
SocketConfig configures an optional real-time websocket used to stream simulation updates.
type SocketConfig struct {
Address string `yaml:"address"`
Handle string `yaml:"handle"`
MillisecondDelay uint64 `yaml:"millisecond_delay"`
// AllowedOrigins lists extra browser origins (e.g. "https://dash.example.com")
// that may connect, beyond the server's own host and loopback hosts; "*"
// admits every origin.
AllowedOrigins []string `yaml:"allowed_origins,omitempty"`
}func LoadSocketConfigFromYaml
func LoadSocketConfigFromYaml(path string) *SocketConfigLoadSocketConfigFromYaml loads a SocketConfig from YAML. If the path is empty, it returns a zero-valued config and logs that sockets are disabled.
func (*SocketConfig) Active
func (s *SocketConfig) Active() boolActive reports whether the websocket server should be started.
type StreamConfig
StreamConfig is a stream input’s transport. Exactly one field is set.
type StreamConfig struct {
// Websocket connects to a websocket server as a client and reads its
// messages.
Websocket *WebsocketStreamConfig `yaml:"websocket,omitempty"`
// Connection reads the messages of the client a run is served to, under
// run: {mode: serve}: the connection its {type: connection} view streams
// to, read in the other direction.
Connection *ConnectionStreamConfig `yaml:"connection,omitempty"`
// Extra holds a transport registered with RegisterStreamTransport, such as
// keyboard, by name.
Extra map[string]map[string]interface{} `yaml:",inline"`
}type StreamSource
StreamSource is one open stream from a registered transport.
type StreamSource interface {
// Read delivers each message the stream produces until the stream ends,
// Close is called, or deliver returns an error.
Read(deliver func(message []byte) error)
// Close stops the stream and releases what it holds.
Close() error
}type StreamTransport
StreamTransport is a registered stream transport: Check validates a config’s fields for it when the config loads, and Open opens it when a run starts.
type StreamTransport struct {
Check func(fields map[string]interface{}) error
Open func(fields map[string]interface{}) (StreamSource, error)
}type WebsocketServeConfig
WebsocketServeConfig is where run: {mode: serve} listens: the websocket is mounted at Handle (“/” when empty) on Address.
type WebsocketServeConfig struct {
Address string `yaml:"address"`
Handle string `yaml:"handle,omitempty"`
// AllowedOrigins lists extra browser origins (e.g. "https://dash.example.com")
// that may connect, beyond the server's own host and loopback hosts; "*"
// admits every origin.
AllowedOrigins []string `yaml:"allowed_origins,omitempty"`
}type WebsocketStreamConfig
WebsocketStreamConfig is a websocket stream’s server address.
type WebsocketStreamConfig struct {
URL string `yaml:"url"`
}Generated by gomarkdoc