Current section
Files
Jump to
Current section
Files
src/liquid_conglomerate/lc_supervisor.erl
%% @doc Liquid Conglomerate Supervisor.
%%
%% Supervises all 13 silos of the Liquid Conglomerate v2 architecture:
%%
%% **Core Silos (Always Enabled):**
%% Task Silo: Evolution optimization (Ï„ = 50)
%% Resource Silo: System stability (Ï„ = 5)
%%
%% **Optional Silos (Enable via Config):**
%% Distribution Silo: Mesh networking (Ï„ = 1)
%% Temporal Silo: Episode timing (Ï„ = 10)
%% Competitive Silo: Opponent archives, Elo (Ï„ = 50)
%% Social Silo: Reputation, coalitions (Ï„ = 50)
%% Cultural Silo: Innovations, traditions (Ï„ = 100)
%% Ecological Silo: Niches, stress (Ï„ = 100)
%% Morphological Silo: Network complexity (Ï„ = 30)
%% Developmental Silo: Ontogeny, plasticity (Ï„ = 100)
%% Regulatory Silo: Gene expression (Ï„ = 50)
%% Economic Silo: Compute budgets (Ï„ = 20)
%% Communication Silo: Vocabulary, coordination (Ï„ = 30)
%%
%% Additionally supervises the meta_controller (L2 strategic layer) when enabled:
%% Meta Controller: LTC-based hierarchical control (outputs L1 guidance)
%%
%% Each silo operates independently with its own hierarchical levels (L0/L1/L2).
%% When meta_controller is enabled, it provides L2 guidance to silos.
%%
%% @author Macula.io
%% @copyright 2025 Macula.io
-module(lc_supervisor).
-behaviour(supervisor).
-include("meta_controller.hrl").
%% API
-export([start_link/0, start_link/1]).
%% Supervisor callbacks
-export([init/1]).
-define(SERVER, ?MODULE).
%%% ============================================================================
%%% API Functions
%%% ============================================================================
%% @doc Start the Liquid Conglomerate supervisor with default configuration.
-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
start_link() ->
start_link(#{}).
%% @doc Start the Liquid Conglomerate supervisor with custom configuration.
%%
%% Config options:
%% resource_silo: Map of resource silo configuration
%% task_silo: Map of task silo configuration (future)
%% distribution_silo: Map of distribution silo configuration (future)
%%
%% If the supervisor is already running, returns the existing pid.
-spec start_link(map()) -> {ok, pid()} | ignore | {error, term()}.
start_link(Config) ->
case whereis(?SERVER) of
undefined ->
supervisor:start_link({local, ?SERVER}, ?MODULE, Config);
Pid when is_pid(Pid) ->
%% Already running, return existing pid
{ok, Pid}
end.
%%% ============================================================================
%%% Supervisor Callbacks
%%% ============================================================================
init(Config) ->
SupFlags = #{
strategy => one_for_one,
intensity => 5,
period => 10
},
%% ========================================================================
%% LC v2 Infrastructure - Cross-Silo Communication
%% ========================================================================
%% Cross-silo coordinator (must start first for signal routing)
CrossSiloConfig = maps:get(cross_silo, Config, #{}),
CrossSiloSpec = #{
id => lc_cross_silo,
start => {lc_cross_silo, start_link, [CrossSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [lc_cross_silo]
},
%% ========================================================================
%% Resource Silo Components
%% ========================================================================
ResourceSiloConfig = maps:get(resource_silo, Config, #{}),
%% Resource L0 Sensors - Collect system metrics
ResourceSensorsSpec = #{
id => resource_l0_sensors,
start => {resource_l0_sensors, start_link, [ResourceSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [resource_l0_sensors]
},
%% Resource L0 Actuators - Apply TWEANN outputs
ResourceActuatorsSpec = #{
id => resource_l0_actuators,
start => {resource_l0_actuators, start_link, [ResourceSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [resource_l0_actuators]
},
%% Resource Silo - Main controller
ResourceSiloSpec = #{
id => resource_silo,
start => {resource_silo, start_link, [ResourceSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [resource_silo]
},
%% ========================================================================
%% Task Silo Components
%% ========================================================================
TaskSiloConfig = maps:get(task_silo, Config, #{}),
%% Task L0 Sensors - Collect evolution statistics
TaskSensorsSpec = #{
id => task_l0_sensors,
start => {task_l0_sensors, start_link, [TaskSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [task_l0_sensors]
},
%% Task L0 Actuators - Apply TWEANN outputs
TaskActuatorsSpec = #{
id => task_l0_actuators,
start => {task_l0_actuators, start_link, [TaskSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [task_l0_actuators]
},
%% Meta Controller (L2) - Strategic layer (optional)
MetaControllerEnabled = maps:get(enable_meta_controller, Config, false),
MetaControllerSpecs = case MetaControllerEnabled of
true ->
MetaControllerConfig = build_meta_config(Config),
[#{
id => meta_controller,
start => {meta_controller, start_link, [MetaControllerConfig, [{name, {local, meta_controller}}]]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [meta_controller]
}];
false ->
[]
end,
%% Task Silo - Main controller
%% L0 TWEANN mode: when enabled, task_silo uses lc_silo_chain for neural network-based
%% hyperparameter control instead of rule-based L1 adjustments
%% Enabled by default for LC v2 architecture
L0TweannEnabled = maps:get(enable_l0_tweann, Config, true),
TaskSiloConfigWithFlags = TaskSiloConfig#{
l2_enabled => MetaControllerEnabled,
l0_tweann_enabled => L0TweannEnabled
},
TaskSiloConfigWithL2 = TaskSiloConfigWithFlags,
TaskSiloSpec = #{
id => task_silo,
start => {task_silo, start_link, [TaskSiloConfigWithL2]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [task_silo]
},
%% ========================================================================
%% Distribution Silo Components (optional, for mesh networking)
%% ========================================================================
DistributionEnabled = maps:get(enable_distribution_silo, Config, false),
DistSiloConfig = maps:get(distribution_silo, Config, #{}),
DistributionSpecs = case DistributionEnabled of
true ->
[
%% Distribution L0 Sensors
#{
id => distribution_l0_sensors,
start => {distribution_l0_sensors, start_link, [DistSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [distribution_l0_sensors]
},
%% Distribution L0 Actuators
#{
id => distribution_l0_actuators,
start => {distribution_l0_actuators, start_link, [DistSiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [distribution_l0_actuators]
}
%% Distribution Silo main controller would go here
];
false ->
[]
end,
%% ========================================================================
%% Extension Silos (LC v2 - Optional)
%% ========================================================================
%%
%% These silos are disabled by default and enabled via configuration.
%% Each silo follows the same pattern: sensors + actuators + main controller.
ExtensionSiloSpecs = build_extension_silo_specs(Config),
%% ========================================================================
%% Child Ordering
%% ========================================================================
%% Order matters for dependency:
%% 1. Cross-silo coordinator (signal routing)
%% 2. Sensors (collect inputs)
%% 3. Actuators (apply outputs)
%% 4. Meta controller (L2 guidance)
%% 5. Main silo controllers
%% 6. Extension silos (optional)
ChildSpecs = [CrossSiloSpec,
ResourceSensorsSpec, ResourceActuatorsSpec,
TaskSensorsSpec, TaskActuatorsSpec]
++ MetaControllerSpecs
++ [ResourceSiloSpec, TaskSiloSpec]
++ DistributionSpecs
++ ExtensionSiloSpecs,
%% Count enabled extension silos
EnabledExtensions = count_enabled_extensions(Config),
error_logger:info_msg("[lc_supervisor] Starting Liquid Conglomerate v2 with ~p children "
"(L2=~p, Distribution=~p, Extensions=~p)~n",
[length(ChildSpecs), MetaControllerEnabled, DistributionEnabled,
EnabledExtensions]),
{ok, {SupFlags, ChildSpecs}}.
%%% ============================================================================
%%% Internal Functions
%%% ============================================================================
%% @doc Build meta_config from supervisor config.
%% Uses defaults with overrides from config map.
-spec build_meta_config(map()) -> meta_config().
build_meta_config(Config) ->
MetaOpts = maps:get(meta_controller, Config, #{}),
%% Default topology: 11 inputs (8 evolution + 3 resource), 5 outputs (L1 guidance)
Topology = maps:get(network_topology, MetaOpts, {11, [24, 16, 8], 5}),
TimeConstant = maps:get(time_constant, MetaOpts, 50.0),
NeuronType = maps:get(neuron_type, MetaOpts, cfc),
LearningRate = maps:get(learning_rate, MetaOpts, 0.001),
#meta_config{
network_topology = Topology,
time_constant = TimeConstant,
neuron_type = NeuronType,
learning_rate = LearningRate
}.
%% @doc Build child specs for extension silos based on configuration.
%%
%% Extension silos are disabled by default. Enable via:
%%
%% Config = #{
%% enable_temporal_silo => true,
%% enable_competitive_silo => true,
%% ...
%% }
%%
%% Each enabled silo adds its child spec to the supervision tree.
%% Silos that aren't implemented yet are logged as warnings.
-spec build_extension_silo_specs(map()) -> [supervisor:child_spec()].
build_extension_silo_specs(Config) ->
%% List of extension silos with their configuration keys and modules
ExtensionSilos = [
{temporal, enable_temporal_silo, temporal_silo, temporal_silo},
{competitive, enable_competitive_silo, competitive_silo, competitive_silo},
{social, enable_social_silo, social_silo, social_silo},
{cultural, enable_cultural_silo, cultural_silo, cultural_silo},
{ecological, enable_ecological_silo, ecological_silo, ecological_silo},
{morphological, enable_morphological_silo, morphological_silo, morphological_silo},
{developmental, enable_developmental_silo, developmental_silo, developmental_silo},
{regulatory, enable_regulatory_silo, regulatory_silo, regulatory_silo},
{economic, enable_economic_silo, economic_silo, economic_silo},
{communication, enable_communication_silo, communication_silo, communication_silo}
],
%% Build specs for enabled silos
lists:filtermap(
fun({SiloType, EnableKey, ModuleName, _Module}) ->
Enabled = maps:get(EnableKey, Config, false),
case Enabled of
true ->
case code:which(ModuleName) of
non_existing ->
error_logger:warning_msg(
"[lc_supervisor] ~p enabled but ~p module not found~n",
[SiloType, ModuleName]
),
false;
_ ->
SiloConfig = maps:get(
list_to_atom(atom_to_list(SiloType) ++ "_silo"),
Config,
#{}
),
Spec = #{
id => ModuleName,
start => {ModuleName, start_link, [SiloConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [ModuleName]
},
{true, Spec}
end;
false ->
false
end
end,
ExtensionSilos
).
%% @doc Count enabled extension silos in configuration.
-spec count_enabled_extensions(map()) -> non_neg_integer().
count_enabled_extensions(Config) ->
EnableKeys = [
enable_temporal_silo,
enable_competitive_silo,
enable_social_silo,
enable_cultural_silo,
enable_ecological_silo,
enable_morphological_silo,
enable_developmental_silo,
enable_regulatory_silo,
enable_economic_silo,
enable_communication_silo
],
lists:foldl(
fun(Key, Count) ->
case maps:get(Key, Config, false) of
true -> Count + 1;
false -> Count
end
end,
0,
EnableKeys
).