Lifecycle
The lifecycle system governs plant-centered ecological change in PHIDS. It is the phase in which flora grow, attempt reproduction, prune stale root-network references, die when energy falls below survival limits, and gradually extend mycorrhizal connectivity.
This chapter documents the current implementation in src/phids/engine/systems/lifecycle.py.
Role in the Engine
run_lifecycle() executes after flow-field generation and camouflage attenuation but before swarm
interaction and signaling.
This ordering matters. The lifecycle phase updates plant state first so that:
- later feeding decisions observe current plant energy,
- later signaling decisions observe the plant population that survived the lifecycle pass,
- the aggregate plant-energy layer is rebuilt before subsequent phases depend on it.
Runtime Inputs
The lifecycle system currently consumes:
ECSWorldfor plant entities and spatial occupancy,GridEnvironmentfor plant-energy writes and layer rebuilds,tickfor growth and reproduction timing,- flora species parameter lookups,
- mycorrhizal settings from the simulation config.
Principal Responsibilities
In its current form, run_lifecycle() performs the following tasks:
- apply growth to each plant,
- attempt reproduction when interval and energy constraints permit,
- write current plant energy into the environment,
- prune dead mycorrhizal links,
- identify and unregister dead plants,
- optionally establish new mycorrhizal links for disjoint plant pairs,
- garbage-collect dead plants,
- rebuild the aggregate plant-energy layer.
Plant Runtime Model
The lifecycle system operates on PlantComponent, which currently stores:
- spatial coordinates,
- current energy,
- max energy,
- base energy,
- growth rate,
- survival threshold,
- reproduction interval,
- seed dispersal bounds,
- seed energy cost,
- camouflage settings,
last_reproduction_tick,last_energy_loss_cause,mycorrhizal_connections.
This means lifecycle is the phase that primarily updates the long-term state trajectory of plant entities.
Growth Model
The helper _grow(plant, tick) now applies an incremental deterministic rule rather than a
global-clock formula:
growth_amount = plant.base_energy * (plant.growth_rate / 100.0)plant.energy = min(plant.energy + growth_amount, plant.max_energy)
This is important because late-born plants no longer inherit fictitious age from the global tick. Growth is now a per-tick integration of species-specific productivity and therefore remains compatible with the simulator’s bounded, current-state plant-energy interpretation.
Reproduction Model
Reproduction is handled by _attempt_reproduction(...).
A plant may attempt reproduction only if:
- enough ticks have elapsed since
last_reproduction_tick, and - the plant can pay
seed_energy_costwhile remaining at or above itssurvival_threshold.
Current behavior includes several important details.
Energy is only spent on valid successful placement
The current implementation no longer burns seed energy on invalid reproduction attempts. Boundary checks, occupancy checks, and species-parameter resolution all happen before the cost is deducted. This means a crowded canopy no longer induces self-starvation merely because stochastic dispersal selects blocked cells.
Dispersal is stochastic but bounded
The target seed location is chosen using:
- a random angle,
- a random distance in
[seed_min_dist, seed_max_dist].
Germination is occupancy-constrained
If the target cell is out of bounds or already contains a plant, the reproduction attempt fails and no offspring is created.
Offspring are spawned as new ECS entities
When reproduction succeeds, the lifecycle system creates a new PlantComponent, registers it in the
spatial hash, writes its initial energy into the environment, and initializes the offspring’s
last_reproduction_tick to its birth tick so newborns cannot bypass the species-specific cooldown.
Mycorrhizal Networking
The lifecycle phase is also responsible for establishing new mycorrhizal links.
Growth cadence
The helper _should_attempt_mycorrhizal_growth(tick, growth_interval_ticks) determines whether the
current lifecycle pass is allowed to form a new root connection.
Current semantics:
- no new link is attempted on most ticks,
- the first attempt occurs only after the configured interval has elapsed,
- an interval of
1permits an attempt every tick.
Deterministic connection ordering
When root growth is attempted, _establish_mycorrhizal_connections(...):
- collects current plants,
- excludes plants already marked dead in this pass,
- sorts plants deterministically by
(y, x, species_id, entity_id), - only checks forward neighbors
(1, 0)and(0, 1).
This ensures deterministic candidate enumeration even though more than one disjoint pair may now form during the same permitted growth tick.
Parallel but bounded growth
The current implementation no longer uses a single global root-growth token. Instead, each plant may form at most one new link during an eligible growth pass, provided the participating pair is disjoint from pairs already formed that tick. This allows sparse and dense biotopes to expand their root networks in parallel while still preventing one plant from opening an arbitrary number of new links in a single lifecycle pass.
Link costs
Both participating plants must be able to pay connection_cost and remain above their individual
survival_threshold values after paying it. When the link is formed:
- each plant loses the configured energy amount,
- both plants receive the bidirectional connection,
- the updated energies are written into the environment.
Species restrictions
When inter_species is false, mycorrhizal links are limited to plants of the same species.
Death and Culling
After growth, reproduction, and energy update, lifecycle checks whether:
plant.energy < plant.survival_threshold
If so, the current implementation:
- clears the plant’s energy contribution in the environment write buffer,
- unregisters the plant from the spatial hash,
- marks the plant for later garbage collection.
Actual destruction is deferred until after the full plant pass completes.
The lifecycle phase also records the most recent energetically relevant action in
last_energy_loss_cause. When a plant is culled here, that marker is used to attribute the immediate
death cause to reproduction, mycorrhizal growth, or background deficit in the telemetry layer.
Read/Write Boundary
Lifecycle mutates plant components in place, but it updates environmental plant energy through the biotope write-side helpers:
env.set_plant_energy(...)env.clear_plant_energy(...)env.rebuild_energy_layer()
This is another example of PHIDS’s current hybrid model:
- entity state is updated directly within the phase,
- field visibility is synchronized through buffered environmental rebuilds.
Ordering Nuances
Several ordering details are important to document explicitly.
Reproduction precedes root-growth attempt
In the current implementation, reproduction happens during the plant iteration before the optional mycorrhizal growth attempt at the end of the phase.
Dead plants are excluded from new root links
Plants marked dead during the pass are excluded from mycorrhizal link formation even before garbage collection occurs.
Layer rebuild occurs once per lifecycle pass
The environment’s aggregate plant-energy layer is rebuilt only after all lifecycle updates and dead entity cleanup are complete.
Evidence from Tests
The current test suite verifies several important lifecycle behaviors.
Mycorrhizal connection cost and bidirectionality
Tests verify that adjacent plants can form links, pay energy cost, and receive reciprocal connections.
Inter-species connection restrictions
Tests verify that the inter-species switch blocks cross-species links when disabled.
Interval-gated parallel root growth
Tests verify that no links form before the configured interval, that disjoint pairs can form in the same eligible tick, and that an individual plant still forms at most one new link per growth pass.
Environmental energy rebuild behavior
Invariant tests verify that plant-energy writes become visible only after rebuild_energy_layer()
and that clearing plant energy is reflected after rebuild.
Reproduction and scenario helpers
Additional coverage tests exercise reproduction and scenario helpers that feed lifecycle behavior.
Methodological Limits of the Current Lifecycle Model
The lifecycle system should be described precisely rather than idealized.
- reproduction uses randomness for seed direction and distance,
- the current growth formula depends on
base_energyand global tick rather than on a purely local incremental energy differential, - mycorrhizal growth is deterministic in order and cadence but intentionally very conservative,
- lifecycle mutates components in place while synchronizing field state through biotope rebuilds.
These are part of the current engine model.
Verified Current-State Evidence
src/phids/engine/systems/lifecycle.pysrc/phids/engine/components/plant.pysrc/phids/engine/loop.pytests/test_systems_behavior.pytests/test_schemas_and_invariants.pytests/test_additional_coverage.py
Where to Read Next
- For the swarm-centered phase that follows lifecycle:
interaction.md - For root-network signal transfer after lifecycle:
signaling.md - For buffered plant-energy visibility:
biotope-and-double-buffering.md