github-actions[bot]
Sync: publish Space API fix
5e0b58b
Raw History Blame Contribute Delete
4.9 kB
"""Canonical structural composition factory.
This module extracts the structural self-organization composition logic
from ``src.main`` so that both production startup and E2E tests use
exactly the same composition path.
The factory creates:
Brain5DManipulator
StructuralJournal
StructuralPlasticityEngine
SelfOrganizationCoordinator
OperatorBridge (optional)
All components reference the same live ``NeuralNetwork`` instance.
This is NOT a test helper. It is the production composition path.
``src.main`` delegates to this factory; tests verify the factory output.
"""
from __future__ import annotations
from pathlib import Path
from typing import Any, cast
from src.controller.runtime import RuntimeController
from src.core.network import NeuralNetwork
from src.dashboard.operator_bridge import OperatorBridge
from src.manipulation.manipulator import Brain5DManipulator
from src.self_organization.coordinator import SelfOrganizationCoordinator
from src.self_organization.plasticity import (
PlasticitySafetyLimits,
StructuralPlasticityEngine,
)
from src.self_organization.policy import (
LegacyStructuralProposal,
ProposalKind,
StructuralProposal,
)
from src.storage.structural_journal import StructuralJournal
def compose_structural_subsystem(
network: NeuralNetwork,
journal_path: Path,
*,
coordinator_enabled: bool = True,
coordinator_dry_run: bool = False,
max_changes_per_tick: int = 1,
allow_neurogenesis: bool = True,
allow_neuron_pruning: bool = True,
allow_synapse_sprouting: bool = True,
allow_synapse_pruning: bool = True,
create_controller: bool = False,
create_bridge: bool = False,
) -> dict[str, Any]:
"""Compose the canonical structural subsystem.
This is the single production composition function. Both ``src.main``
and E2E tests call this — tests do NOT recreate a parallel architecture.
Args:
network: The live NeuralNetwork (shared by all components).
journal_path: Path for the StructuralJournal file.
coordinator_enabled: Whether the coordinator accepts proposals.
coordinator_dry_run: If True, coordinator stores but never executes.
max_changes_per_tick: Rate limit for structural changes.
allow_neurogenesis: Permit neuron creation proposals.
allow_neuron_pruning: Permit neuron removal proposals.
allow_synapse_sprouting: Permit synapse creation proposals.
allow_synapse_pruning: Permit synapse removal proposals.
create_controller: If True, create a RuntimeController for the network.
create_bridge: If True, create an OperatorBridge wrapping everything.
Returns:
A dict with keys: manipulator, journal, plasticity, coordinator,
and optionally controller, bridge.
"""
manipulator = Brain5DManipulator(network)
journal = StructuralJournal(journal_path)
plasticity = StructuralPlasticityEngine(
manipulator=manipulator,
journal=journal,
limits=PlasticitySafetyLimits(
max_changes_per_tick=max_changes_per_tick,
allow_neurogenesis=allow_neurogenesis,
allow_neuron_pruning=allow_neuron_pruning,
allow_synapse_sprouting=allow_synapse_sprouting,
allow_synapse_pruning=allow_synapse_pruning,
),
)
def _plasticity_executor(proposal: LegacyStructuralProposal) -> int:
"""Adapter: translate LegacyStructuralProposal to apply_proposal call."""
kind_map = {
"neurogenesis": ProposalKind.NEUROGENESIS,
"prune": ProposalKind.PRUNING,
}
sp = StructuralProposal(
proposal_id=f"legacy-{proposal.tick}-{proposal.action.value}",
kind=kind_map.get(proposal.action.value, ProposalKind.NEUROGENESIS),
reason=proposal.reason,
)
change = plasticity.apply_proposal(
tick=int(network.current_tick),
proposal=sp,
approved=True,
)
return 1 if change is not None else 0
coordinator = SelfOrganizationCoordinator(
executor=_plasticity_executor,
enabled=coordinator_enabled,
dry_run=coordinator_dry_run,
)
result: dict[str, Any] = {
"manipulator": manipulator,
"journal": journal,
"plasticity": plasticity,
"coordinator": coordinator,
}
if create_controller:
result["controller"] = RuntimeController(network)
if create_bridge:
controller = result.get("controller")
if controller is None:
controller = RuntimeController(network)
result["controller"] = controller
result["bridge"] = OperatorBridge(
controller=cast(RuntimeController, controller),
coordinator=coordinator,
plasticity=plasticity,
)
return result