Current section
Files
Jump to
Current section
Files
src/liquid_conglomerate/lc_supervisor.erl
%% @doc Liquid Conglomerate Supervisor.
%%
%% Supervises all 3 silos of the Liquid Conglomerate v2 architecture:
%% - Task Silo: Evolution optimization (Ï„ = 50)
%% - Resource Silo: System stability (Ï„ = 5)
%% - Distribution Silo: Mesh optimization (Ï„ = 1)
%%
%% 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 task_silo.
%%
%% @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,
%% ========================================================================
%% 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
ChildSpecs = [CrossSiloSpec,
ResourceSensorsSpec, ResourceActuatorsSpec,
TaskSensorsSpec, TaskActuatorsSpec]
++ MetaControllerSpecs
++ [ResourceSiloSpec, TaskSiloSpec]
++ DistributionSpecs,
error_logger:info_msg("[lc_supervisor] Starting Liquid Conglomerate v2 with ~p children "
"(L2=~p, Distribution=~p)~n",
[length(ChildSpecs), MetaControllerEnabled, DistributionEnabled]),
{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
}.