# `Monty.Config.Source`
[🔗](https://github.com/d-led/ex.tbp.monty/blob/v0.1.0/packages/ex_tbp_monty_core/lib/monty/config/source.ex#L1)

Reads Monty's own Hydra/OmegaConf config files.

The promise this module exists for: a config that Monty ships can be handed
to this application unchanged. Nothing here knows what an experiment *means*;
it only knows how Hydra lays one out on disk.

What is implemented is the subset Monty actually uses (checked against its
`conf/` tree): a `defaults:` list, `_self_`, `# @package` headers, and
`group@package` overrides. There is no `override` syntax, no `optional:`
marker and no CLI group override in the tree, so none of those are invented
here.

# `config`

```elixir
@type config() :: %{
  package: [String.t()] | nil,
  defaults: [default()],
  body: map() | nil,
  file: Path.t()
}
```

# `default`

```elixir
@type default() ::
  :self | {:group, String.t(), String.t() | :missing, String.t() | nil}
```

# `conf_dir`

```elixir
@spec conf_dir() :: Path.t()
```

The config tree to compose from.

The shipped copy by default; `conf_dir/1` names the same tree inside a
checkout, which is what a person comparing against an upstream pull wants.

# `conf_dir`

```elixir
@spec conf_dir(Path.t()) :: Path.t()
```

The Hydra config directory inside a Monty checkout.

# `default_package`

```elixir
@spec default_package(String.t()) :: [String.t()]
```

The package a group's config lands in when the file does not say.

Hydra's default package for `- group: option` is the group path with dots, so
`monty/connectivity` lands at `monty.connectivity` unless a `# @package`
header overrides it. Monty's files almost always override it; this is the
fallback that makes the rule complete.

# `experiments`

```elixir
@spec experiments(Path.t()) :: [String.t()]
```

Names of the experiments Monty ships, relative to the `experiment` group and
without the `.yaml` suffix.

Nested directories (`test/`, `tutorial/`) are included with their prefix, so
`test/run` is a name an experiment can be launched by.

# `inputs_root`

```elixir
@spec inputs_root() :: Path.t()
```

The Monty inputs this application ships: the Hydra configs it composes and the
snapshots it checks them against.

Copied from a checkout by `mix monty.inputs` and checked in, so that building
the image, running the suite and running CI need no Monty checkout.
`:code.priv_dir/1` rather than a relative `priv/`, because a release runs from
`bin/` while its files live under `lib/`.

# `load`

```elixir
@spec load(Path.t(), String.t(), String.t()) :: {:ok, config()} | {:error, term()}
```

Loads one config file of a group.

# `load_file`

```elixir
@spec load_file(Path.t()) :: {:ok, config()} | {:error, term()}
```

Loads a config file by path, wherever it lives.

# `load_text`

```elixir
@spec load_text(String.t(), Path.t()) :: {:ok, config()} | {:error, term()}
```

Parses config text as if it were the file at `path`.

This is what makes a generated config the same kind of thing as one Monty
ships: it is composed from its text, not from a struct that would have to
keep its own idea of what the text means.

# `path_for`

```elixir
@spec path_for(Path.t(), String.t(), String.t()) :: Path.t()
```

The file a group option lives in.

# `root`

```elixir
@spec root() :: Path.t()
```

The Monty checkout: a maintainer's input, never a running system's.

`MONTY_SOURCE` wins; otherwise `../monty-orig` next to the project, which is
where the reference checkout lives in this workspace. What reads it: the mix
tasks that regenerate from upstream (`mix monty.inputs`, `mix monty.module_map`,
`mix monty.port_census`) and the tests of those tasks. Reading a neighbouring
checkout is a *development* thing — copying its files in, comparing against
it — and the image does not carry one, so nothing a release runs may fall back
to this path: a tool that needs documentation or roadmap data reads the
project's published site, and one that needs configs reads those `priv/monty`
already ships.

# `snapshots_dir`

```elixir
@spec snapshots_dir() :: Path.t()
```

The snapshots to check composed configs against, shipped with them.

# `snapshots_dir`

```elixir
@spec snapshots_dir(Path.t()) :: Path.t()
```

The snapshot directory inside a Monty checkout.

# `teleop_root`

```elixir
@spec teleop_root() :: Path.t()
```

The teleop checkout to read from.

`TELEOP_SOURCE` wins; otherwise `../tbp.teleop` next to the project, which is
where the reference checkout lives in this workspace.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
