skip to content

gen-settings

gen-settings resolves an aspect’s settings — a static, introspectable schema of { default; merge } leaves — against an ordered list of override layers, producing a resolved value plus a full per-field provenance chain.

The problem it owns: “why does this field have this value” needs a real answer once more than one layer can set it — env defaults, host overrides, an explicit per-node value. gen-settings resolves the merge and keeps the chain that produced it, so the answer to “why” is a lookup, not an investigation.

It has the largest dependency footprint on the roster: gen-algebra, gen-bind, gen-graph, gen-identity, gen-prelude, gen-schema, and gen-types. No roster member currently builds on gen-settings.

let
genSettings = (import ./lib) {
prelude = gen-prelude.lib;
algebra = gen-algebra.lib;
bind = gen-bind.lib;
graph = gen-graph.lib;
};
inherit (genSettings) mkSchema resolveOne;
schema = mkSchema {
aspect = config.aspects.firewall; # a registry entry (carries id_hash)
fields = {
"allowed-tcp" = { default = [ 22 ]; merge = "append"; };
hostname = { default = "unset"; }; # replace (implicit)
};
};
resolved = resolveOne {
inherit schema;
layers = [
{ scope = { env = config.envs.prod; }; rendered = "prod"; via = null;
value = { "allowed-tcp" = [ 80 ]; }; }
{ scope = { host = den.hosts.axon-01; }; rendered = "axon-01"; via = null;
value = { "allowed-tcp" = [ 443 ]; hostname = "axon-01"; }; }
];
};
in
resolved.value # => { "allowed-tcp" = [ 22 80 443 ]; hostname = "axon-01"; }
palette
dark
light
↑↓ select apply esc close

Palettes adapted from Catppuccin (Macchiato) (MIT), Tokyo Night (Apache-2.0), gruvbox (MIT), Catppuccin (Latte) (MIT), Rosé Pine (Dawn) (MIT).