%% @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 }.