Current section
Files
Jump to
Current section
Files
src/evolve/neuroevolution_behavioral_events.erl
%%%-------------------------------------------------------------------
%%% @doc Behavioral event constructors for neuroevolution.
%%%
%%% This module provides helper functions to construct properly-formed
%%% behavioral events. All events include standard metadata and follow
%%% the behavioral naming conventions (past tense, domain language).
%%%
%%% == Usage ==
%%%
%%% ```
%%% Event = neuroevolution_behavioral_events:offspring_born(#{
%%% individual_id => IndId,
%%% parent_ids => [P1, P2],
%%% generation => 42,
%%% species_id => SpeciesId,
%%% population_id => PopId
%%% }),
%%% neuroevolution_lineage_events:persist_event(Event, State).
%%% '''
%%%
%%% @end
%%%-------------------------------------------------------------------
-module(neuroevolution_behavioral_events).
-include("neuroevolution_behavioral_events.hrl").
%% Event constructors - Birth
-export([
offspring_born/1,
pioneer_spawned/1,
clone_produced/1,
immigrant_arrived/1
]).
%% Event constructors - Death
-export([
individual_culled/1,
lifespan_expired/1,
individual_perished/1
]).
%% Event constructors - Mutation
-export([
mutation_applied/1,
neuron_added/1,
neuron_removed/1,
connection_added/1,
connection_removed/1,
weight_perturbed/1,
bias_perturbed/1,
activation_changed/1
]).
%% Event constructors - Fitness
-export([
fitness_evaluated/1,
fitness_improved/1,
fitness_declined/1,
champion_crowned/1,
evaluation_timeout/1,
stagnation_detected/1,
breakthrough_achieved/1
]).
%% Event constructors - Generation
-export([
generation_completed/1,
population_initialized/1,
population_terminated/1
]).
%% Event constructors - Species
-export([
lineage_diverged/1,
species_emerged/1,
lineage_ended/1
]).
%% Event constructors - Breeding
-export([
mating_occurred/1,
crossover_performed/1
]).
%% Event constructors - Lifecycle
-export([
individual_matured/1,
fertility_waned/1
]).
%% Event constructors - Controller
-export([
controller_adjusted/1,
silo_activated/1,
silo_deactivated/1
]).
%% Utility exports
-export([
make_meta/1,
make_meta/2,
event_to_map/1,
stream_id/2
]).
%%% ============================================================================
%%% Metadata Construction
%%% ============================================================================
%% @doc Create event metadata with default values.
-spec make_meta(Emitter :: atom()) -> #event_meta{}.
make_meta(Emitter) ->
make_meta(Emitter, #{}).
%% @doc Create event metadata with options.
-spec make_meta(Emitter :: atom(), Opts :: map()) -> #event_meta{}.
make_meta(Emitter, Opts) ->
#event_meta{
event_id = maps:get(event_id, Opts, generate_id()),
correlation_id = maps:get(correlation_id, Opts, undefined),
causation_id = maps:get(causation_id, Opts, undefined),
timestamp = maps:get(timestamp, Opts, erlang:system_time(microsecond)),
version = maps:get(version, Opts, 1),
emitter = Emitter
}.
%%% ============================================================================
%%% Birth Event Constructors
%%% ============================================================================
%% @doc Create offspring_born event.
-spec offspring_born(map()) -> #offspring_born{}.
offspring_born(Data) ->
#offspring_born{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
individual_id = maps:get(individual_id, Data),
parent_ids = maps:get(parent_ids, Data),
generation = maps:get(generation, Data),
species_id = maps:get(species_id, Data),
population_id = maps:get(population_id, Data),
genome_hash = maps:get(genome_hash, Data, <<>>),
initial_fitness = maps:get(initial_fitness, Data, undefined)
}.
%% @doc Create pioneer_spawned event.
-spec pioneer_spawned(map()) -> #pioneer_spawned{}.
pioneer_spawned(Data) ->
#pioneer_spawned{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
species_id = maps:get(species_id, Data),
generation = maps:get(generation, Data, 0),
genome_hash = maps:get(genome_hash, Data, <<>>)
}.
%% @doc Create clone_produced event.
-spec clone_produced(map()) -> #clone_produced{}.
clone_produced(Data) ->
#clone_produced{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
individual_id = maps:get(individual_id, Data),
parent_id = maps:get(parent_id, Data),
generation = maps:get(generation, Data),
species_id = maps:get(species_id, Data),
population_id = maps:get(population_id, Data),
mutation_applied = maps:get(mutation_applied, Data, false)
}.
%% @doc Create immigrant_arrived event.
-spec immigrant_arrived(map()) -> #immigrant_arrived{}.
immigrant_arrived(Data) ->
#immigrant_arrived{
meta = make_meta(maps:get(emitter, Data, migration_server), Data),
individual_id = maps:get(individual_id, Data),
source_population_id = maps:get(source_population_id, Data),
target_population_id = maps:get(target_population_id, Data),
source_species_id = maps:get(source_species_id, Data),
target_species_id = maps:get(target_species_id, Data),
fitness = maps:get(fitness, Data)
}.
%%% ============================================================================
%%% Death Event Constructors
%%% ============================================================================
%% @doc Create individual_culled event.
-spec individual_culled(map()) -> #individual_culled{}.
individual_culled(Data) ->
#individual_culled{
meta = make_meta(maps:get(emitter, Data, selection_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
species_id = maps:get(species_id, Data),
final_fitness = maps:get(final_fitness, Data),
age_generations = maps:get(age_generations, Data, 0),
cause = maps:get(cause, Data, selection),
lineage_depth = maps:get(lineage_depth, Data, 0)
}.
%% @doc Create lifespan_expired event.
-spec lifespan_expired(map()) -> #lifespan_expired{}.
lifespan_expired(Data) ->
#lifespan_expired{
meta = make_meta(maps:get(emitter, Data, lifecycle_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
age_generations = maps:get(age_generations, Data),
lifecycle_stage = senescent,
peak_fitness = maps:get(peak_fitness, Data),
offspring_count = maps:get(offspring_count, Data, 0)
}.
%% @doc Create individual_perished event.
-spec individual_perished(map()) -> #individual_perished{}.
individual_perished(Data) ->
#individual_perished{
meta = make_meta(maps:get(emitter, Data, evaluation_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
cause = maps:get(cause, Data),
generation = maps:get(generation, Data)
}.
%%% ============================================================================
%%% Mutation Event Constructors
%%% ============================================================================
%% @doc Create mutation_applied event.
-spec mutation_applied(map()) -> #mutation_applied{}.
mutation_applied(Data) ->
#mutation_applied{
meta = make_meta(maps:get(emitter, Data, genome_mutator), Data),
individual_id = maps:get(individual_id, Data),
mutation_id = maps:get(mutation_id, Data, generate_id()),
mutation_type = maps:get(mutation_type, Data),
generation = maps:get(generation, Data)
}.
%% @doc Create neuron_added event.
-spec neuron_added(map()) -> #neuron_added{}.
neuron_added(Data) ->
#neuron_added{
meta = make_meta(maps:get(emitter, Data, topological_mutations), Data),
individual_id = maps:get(individual_id, Data),
neuron_id = maps:get(neuron_id, Data),
layer = maps:get(layer, Data),
layer_index = maps:get(layer_index, Data, 0.5),
activation_function = maps:get(activation_function, Data, tanh),
bias = maps:get(bias, Data, 0.0),
mutation_id = maps:get(mutation_id, Data, generate_id())
}.
%% @doc Create neuron_removed event.
-spec neuron_removed(map()) -> #neuron_removed{}.
neuron_removed(Data) ->
#neuron_removed{
meta = make_meta(maps:get(emitter, Data, topological_mutations), Data),
individual_id = maps:get(individual_id, Data),
neuron_id = maps:get(neuron_id, Data),
layer = maps:get(layer, Data),
mutation_id = maps:get(mutation_id, Data, generate_id())
}.
%% @doc Create connection_added event.
-spec connection_added(map()) -> #connection_added{}.
connection_added(Data) ->
#connection_added{
meta = make_meta(maps:get(emitter, Data, topological_mutations), Data),
individual_id = maps:get(individual_id, Data),
connection_id = maps:get(connection_id, Data),
from_neuron_id = maps:get(from_neuron_id, Data),
to_neuron_id = maps:get(to_neuron_id, Data),
weight = maps:get(weight, Data),
mutation_id = maps:get(mutation_id, Data, generate_id())
}.
%% @doc Create connection_removed event.
-spec connection_removed(map()) -> #connection_removed{}.
connection_removed(Data) ->
#connection_removed{
meta = make_meta(maps:get(emitter, Data, topological_mutations), Data),
individual_id = maps:get(individual_id, Data),
connection_id = maps:get(connection_id, Data),
from_neuron_id = maps:get(from_neuron_id, Data),
to_neuron_id = maps:get(to_neuron_id, Data),
mutation_id = maps:get(mutation_id, Data, generate_id())
}.
%% @doc Create weight_perturbed event.
-spec weight_perturbed(map()) -> #weight_perturbed{}.
weight_perturbed(Data) ->
#weight_perturbed{
meta = make_meta(maps:get(emitter, Data, weight_mutations), Data),
individual_id = maps:get(individual_id, Data),
connection_id = maps:get(connection_id, Data),
old_weight = maps:get(old_weight, Data),
new_weight = maps:get(new_weight, Data),
mutation_id = maps:get(mutation_id, Data, generate_id())
}.
%% @doc Create bias_perturbed event.
-spec bias_perturbed(map()) -> #bias_perturbed{}.
bias_perturbed(Data) ->
#bias_perturbed{
meta = make_meta(maps:get(emitter, Data, weight_mutations), Data),
individual_id = maps:get(individual_id, Data),
neuron_id = maps:get(neuron_id, Data),
old_bias = maps:get(old_bias, Data),
new_bias = maps:get(new_bias, Data),
mutation_id = maps:get(mutation_id, Data, generate_id())
}.
%% @doc Create activation_changed event.
-spec activation_changed(map()) -> #activation_changed{}.
activation_changed(Data) ->
#activation_changed{
meta = make_meta(maps:get(emitter, Data, topological_mutations), Data),
individual_id = maps:get(individual_id, Data),
neuron_id = maps:get(neuron_id, Data),
old_activation = maps:get(old_activation, Data),
new_activation = maps:get(new_activation, Data),
mutation_id = maps:get(mutation_id, Data, generate_id())
}.
%%% ============================================================================
%%% Fitness Event Constructors
%%% ============================================================================
%% @doc Create fitness_evaluated event.
-spec fitness_evaluated(map()) -> #fitness_evaluated{}.
fitness_evaluated(Data) ->
#fitness_evaluated{
meta = make_meta(maps:get(emitter, Data, evaluation_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
fitness = maps:get(fitness, Data),
fitness_components = maps:get(fitness_components, Data, #{}),
evaluation_duration_ms = maps:get(evaluation_duration_ms, Data, 0),
generation = maps:get(generation, Data)
}.
%% @doc Create fitness_improved event.
-spec fitness_improved(map()) -> #fitness_improved{}.
fitness_improved(Data) ->
#fitness_improved{
meta = make_meta(maps:get(emitter, Data, evaluation_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
previous_fitness = maps:get(previous_fitness, Data),
new_fitness = maps:get(new_fitness, Data),
improvement = maps:get(improvement, Data),
generation = maps:get(generation, Data)
}.
%% @doc Create fitness_declined event.
-spec fitness_declined(map()) -> #fitness_declined{}.
fitness_declined(Data) ->
#fitness_declined{
meta = make_meta(maps:get(emitter, Data, evaluation_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
previous_fitness = maps:get(previous_fitness, Data),
new_fitness = maps:get(new_fitness, Data),
decline = maps:get(decline, Data),
generation = maps:get(generation, Data)
}.
%% @doc Create champion_crowned event.
-spec champion_crowned(map()) -> #champion_crowned{}.
champion_crowned(Data) ->
#champion_crowned{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
fitness = maps:get(fitness, Data),
previous_champion_id = maps:get(previous_champion_id, Data, undefined),
previous_champion_fitness = maps:get(previous_champion_fitness, Data, undefined),
generation = maps:get(generation, Data)
}.
%% @doc Create evaluation_timeout event.
-spec evaluation_timeout(map()) -> #evaluation_timeout{}.
evaluation_timeout(Data) ->
#evaluation_timeout{
meta = make_meta(maps:get(emitter, Data, evaluation_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
timeout_ms = maps:get(timeout_ms, Data),
generation = maps:get(generation, Data)
}.
%% @doc Create stagnation_detected event.
-spec stagnation_detected(map()) -> #stagnation_detected{}.
stagnation_detected(Data) ->
#stagnation_detected{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
population_id = maps:get(population_id, Data),
generations_stagnant = maps:get(generations_stagnant, Data),
best_fitness = maps:get(best_fitness, Data),
generation = maps:get(generation, Data)
}.
%% @doc Create breakthrough_achieved event.
-spec breakthrough_achieved(map()) -> #breakthrough_achieved{}.
breakthrough_achieved(Data) ->
#breakthrough_achieved{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
previous_best = maps:get(previous_best, Data),
new_best = maps:get(new_best, Data),
improvement_ratio = maps:get(improvement_ratio, Data),
generation = maps:get(generation, Data)
}.
%%% ============================================================================
%%% Generation Event Constructors
%%% ============================================================================
%% @doc Create generation_completed event.
-spec generation_completed(map()) -> #generation_completed{}.
generation_completed(Data) ->
#generation_completed{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
population_id = maps:get(population_id, Data),
generation = maps:get(generation, Data),
statistics = maps:get(statistics, Data, #{}),
champion_id = maps:get(champion_id, Data),
duration_ms = maps:get(duration_ms, Data, 0)
}.
%% @doc Create population_initialized event.
-spec population_initialized(map()) -> #population_initialized{}.
population_initialized(Data) ->
#population_initialized{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
population_id = maps:get(population_id, Data),
initial_size = maps:get(initial_size, Data),
config = maps:get(config, Data, #{})
}.
%% @doc Create population_terminated event.
-spec population_terminated(map()) -> #population_terminated{}.
population_terminated(Data) ->
#population_terminated{
meta = make_meta(maps:get(emitter, Data, population_server), Data),
population_id = maps:get(population_id, Data),
final_generation = maps:get(final_generation, Data),
reason = maps:get(reason, Data),
final_champion_id = maps:get(final_champion_id, Data),
final_champion_fitness = maps:get(final_champion_fitness, Data)
}.
%%% ============================================================================
%%% Species Event Constructors
%%% ============================================================================
%% @doc Create lineage_diverged event.
-spec lineage_diverged(map()) -> #lineage_diverged{}.
lineage_diverged(Data) ->
#lineage_diverged{
meta = make_meta(maps:get(emitter, Data, speciation_server), Data),
new_species_id = maps:get(new_species_id, Data),
parent_species_id = maps:get(parent_species_id, Data),
founder_individual_id = maps:get(founder_individual_id, Data),
divergence_cause = maps:get(divergence_cause, Data, structural),
compatibility_distance = maps:get(compatibility_distance, Data),
generation = maps:get(generation, Data)
}.
%% @doc Create species_emerged event.
-spec species_emerged(map()) -> #species_emerged{}.
species_emerged(Data) ->
#species_emerged{
meta = make_meta(maps:get(emitter, Data, speciation_server), Data),
species_id = maps:get(species_id, Data),
population_id = maps:get(population_id, Data),
founder_id = maps:get(founder_id, Data),
generation = maps:get(generation, Data)
}.
%% @doc Create lineage_ended event.
-spec lineage_ended(map()) -> #lineage_ended{}.
lineage_ended(Data) ->
#lineage_ended{
meta = make_meta(maps:get(emitter, Data, speciation_server), Data),
species_id = maps:get(species_id, Data),
population_id = maps:get(population_id, Data),
final_generation = maps:get(final_generation, Data),
total_generations = maps:get(total_generations, Data),
peak_fitness = maps:get(peak_fitness, Data),
total_individuals = maps:get(total_individuals, Data)
}.
%%% ============================================================================
%%% Breeding Event Constructors
%%% ============================================================================
%% @doc Create mating_occurred event.
-spec mating_occurred(map()) -> #mating_occurred{}.
mating_occurred(Data) ->
#mating_occurred{
meta = make_meta(maps:get(emitter, Data, breeding_server), Data),
parent_a_id = maps:get(parent_a_id, Data),
parent_b_id = maps:get(parent_b_id, Data),
offspring_ids = maps:get(offspring_ids, Data),
crossover_method = maps:get(crossover_method, Data),
compatibility_distance = maps:get(compatibility_distance, Data),
relatedness_coefficient = maps:get(relatedness_coefficient, Data, 0.0)
}.
%% @doc Create crossover_performed event.
-spec crossover_performed(map()) -> #crossover_performed{}.
crossover_performed(Data) ->
#crossover_performed{
meta = make_meta(maps:get(emitter, Data, crossover_server), Data),
parent_a_id = maps:get(parent_a_id, Data),
parent_b_id = maps:get(parent_b_id, Data),
offspring_id = maps:get(offspring_id, Data),
crossover_point = maps:get(crossover_point, Data),
genes_from_a = maps:get(genes_from_a, Data),
genes_from_b = maps:get(genes_from_b, Data)
}.
%%% ============================================================================
%%% Lifecycle Event Constructors
%%% ============================================================================
%% @doc Create individual_matured event.
-spec individual_matured(map()) -> #individual_matured{}.
individual_matured(Data) ->
#individual_matured{
meta = make_meta(maps:get(emitter, Data, lifecycle_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
previous_stage = juvenile,
new_stage = fertile,
age_generations = maps:get(age_generations, Data),
fitness_at_maturity = maps:get(fitness_at_maturity, Data)
}.
%% @doc Create fertility_waned event.
-spec fertility_waned(map()) -> #fertility_waned{}.
fertility_waned(Data) ->
#fertility_waned{
meta = make_meta(maps:get(emitter, Data, lifecycle_server), Data),
individual_id = maps:get(individual_id, Data),
population_id = maps:get(population_id, Data),
previous_stage = fertile,
new_stage = senescent,
age_generations = maps:get(age_generations, Data),
offspring_count = maps:get(offspring_count, Data, 0)
}.
%%% ============================================================================
%%% Controller Event Constructors
%%% ============================================================================
%% @doc Create controller_adjusted event.
-spec controller_adjusted(map()) -> #controller_adjusted{}.
controller_adjusted(Data) ->
#controller_adjusted{
meta = make_meta(maps:get(emitter, Data, lc_controller), Data),
controller_id = maps:get(controller_id, Data),
population_id = maps:get(population_id, Data),
adjustments = maps:get(adjustments, Data),
trigger = maps:get(trigger, Data)
}.
%% @doc Create silo_activated event.
-spec silo_activated(map()) -> #silo_activated{}.
silo_activated(Data) ->
#silo_activated{
meta = make_meta(maps:get(emitter, Data, lc_supervisor), Data),
silo_type = maps:get(silo_type, Data),
realm = maps:get(realm, Data),
config = maps:get(config, Data, #{})
}.
%% @doc Create silo_deactivated event.
-spec silo_deactivated(map()) -> #silo_deactivated{}.
silo_deactivated(Data) ->
#silo_deactivated{
meta = make_meta(maps:get(emitter, Data, lc_supervisor), Data),
silo_type = maps:get(silo_type, Data),
realm = maps:get(realm, Data),
reason = maps:get(reason, Data, manual)
}.
%%% ============================================================================
%%% Utility Functions
%%% ============================================================================
%% @doc Convert an event record to a map for serialization.
-spec event_to_map(behavioral_event()) -> map().
event_to_map(Event) when is_tuple(Event) ->
[RecordName | Fields] = tuple_to_list(Event),
FieldNames = record_fields(RecordName),
MetaMap = meta_to_map(hd(Fields)),
DataMap = maps:from_list(lists:zip(tl(FieldNames), tl(Fields))),
maps:merge(#{event_type => RecordName, meta => MetaMap}, DataMap).
%% @doc Generate stream ID for an entity.
-spec stream_id(Type :: atom(), Id :: binary()) -> binary().
stream_id(individual, Id) -> <<"individual-", Id/binary>>;
stream_id(species, Id) -> <<"species-", Id/binary>>;
stream_id(population, Id) -> <<"population-", Id/binary>>;
stream_id(coalition, Id) -> <<"coalition-", Id/binary>>;
stream_id(lineage, Id) -> <<"lineage-", Id/binary>>.
%%% ============================================================================
%%% Internal Functions
%%% ============================================================================
generate_id() ->
Bytes = crypto:strong_rand_bytes(16),
binary:encode_hex(Bytes).
meta_to_map(#event_meta{} = Meta) ->
#{
event_id => Meta#event_meta.event_id,
correlation_id => Meta#event_meta.correlation_id,
causation_id => Meta#event_meta.causation_id,
timestamp => Meta#event_meta.timestamp,
version => Meta#event_meta.version,
emitter => Meta#event_meta.emitter
}.
record_fields(offspring_born) -> [meta, individual_id, parent_ids, generation, species_id, population_id, genome_hash, initial_fitness];
record_fields(pioneer_spawned) -> [meta, individual_id, population_id, species_id, generation, genome_hash];
record_fields(clone_produced) -> [meta, individual_id, parent_id, generation, species_id, population_id, mutation_applied];
record_fields(immigrant_arrived) -> [meta, individual_id, source_population_id, target_population_id, source_species_id, target_species_id, fitness];
record_fields(individual_culled) -> [meta, individual_id, population_id, species_id, final_fitness, age_generations, cause, lineage_depth];
record_fields(lifespan_expired) -> [meta, individual_id, population_id, age_generations, lifecycle_stage, peak_fitness, offspring_count];
record_fields(individual_perished) -> [meta, individual_id, population_id, cause, generation];
record_fields(mutation_applied) -> [meta, individual_id, mutation_id, mutation_type, generation];
record_fields(neuron_added) -> [meta, individual_id, neuron_id, layer, layer_index, activation_function, bias, mutation_id];
record_fields(neuron_removed) -> [meta, individual_id, neuron_id, layer, mutation_id];
record_fields(connection_added) -> [meta, individual_id, connection_id, from_neuron_id, to_neuron_id, weight, mutation_id];
record_fields(connection_removed) -> [meta, individual_id, connection_id, from_neuron_id, to_neuron_id, mutation_id];
record_fields(weight_perturbed) -> [meta, individual_id, connection_id, old_weight, new_weight, mutation_id];
record_fields(bias_perturbed) -> [meta, individual_id, neuron_id, old_bias, new_bias, mutation_id];
record_fields(activation_changed) -> [meta, individual_id, neuron_id, old_activation, new_activation, mutation_id];
record_fields(fitness_evaluated) -> [meta, individual_id, population_id, fitness, fitness_components, evaluation_duration_ms, generation];
record_fields(fitness_improved) -> [meta, individual_id, population_id, previous_fitness, new_fitness, improvement, generation];
record_fields(fitness_declined) -> [meta, individual_id, population_id, previous_fitness, new_fitness, decline, generation];
record_fields(champion_crowned) -> [meta, individual_id, population_id, fitness, previous_champion_id, previous_champion_fitness, generation];
record_fields(evaluation_timeout) -> [meta, individual_id, population_id, timeout_ms, generation];
record_fields(stagnation_detected) -> [meta, population_id, generations_stagnant, best_fitness, generation];
record_fields(breakthrough_achieved) -> [meta, individual_id, population_id, previous_best, new_best, improvement_ratio, generation];
record_fields(generation_completed) -> [meta, population_id, generation, statistics, champion_id, duration_ms];
record_fields(population_initialized) -> [meta, population_id, initial_size, config];
record_fields(population_terminated) -> [meta, population_id, final_generation, reason, final_champion_id, final_champion_fitness];
record_fields(lineage_diverged) -> [meta, new_species_id, parent_species_id, founder_individual_id, divergence_cause, compatibility_distance, generation];
record_fields(species_emerged) -> [meta, species_id, population_id, founder_id, generation];
record_fields(lineage_ended) -> [meta, species_id, population_id, final_generation, total_generations, peak_fitness, total_individuals];
record_fields(mating_occurred) -> [meta, parent_a_id, parent_b_id, offspring_ids, crossover_method, compatibility_distance, relatedness_coefficient];
record_fields(crossover_performed) -> [meta, parent_a_id, parent_b_id, offspring_id, crossover_point, genes_from_a, genes_from_b];
record_fields(individual_matured) -> [meta, individual_id, population_id, previous_stage, new_stage, age_generations, fitness_at_maturity];
record_fields(fertility_waned) -> [meta, individual_id, population_id, previous_stage, new_stage, age_generations, offspring_count];
record_fields(controller_adjusted) -> [meta, controller_id, population_id, adjustments, trigger];
record_fields(silo_activated) -> [meta, silo_type, realm, config];
record_fields(silo_deactivated) -> [meta, silo_type, realm, reason].