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

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) error

Check 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) error

CheckForDeadlock 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) error

Execute 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) int

ExitCode 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.Handler

NewWebsocketHandler 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() []string

RegisteredEnvironments 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:

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) *ApiRunConfig

LoadApiRunConfigFromYaml 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:

Returns:

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:

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() []string

Deprecations are notices for the deprecated forms the config uses, each naming its replacement.

func (*ApiRunConfig) GetConfigGenerator

func (a *ApiRunConfig) GetConfigGenerator() *simulator.ConfigGenerator

GetConfigGenerator 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() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type 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 int

const (
    // 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) ErrorKind

KindOf 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) *IOManifest

Manifest 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)) LoadOption

WithEnv 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) LoadOption

WithSet 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) error

UnmarshalYAML 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() ParsedArgs

ArgParse 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:

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:

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.ConfigGenerator

GetConfigGenerator 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:

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) RunOption

CaptureView 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() RunOption

WithConfigOutputs 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) *SocketConfig

LoadSocketConfigFromYaml 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() bool

Active 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