Models

Core data models and types used throughout Babylon.

Pydantic models for the Babylon simulation engine.

This package contains the type system foundation: - enums: Categorical types (SocialRole, EdgeType, etc.) - types: Constrained value types (Probability, Currency, etc.) - entities: Game objects (Effect, Contradiction, Trigger, etc.) - components: Entity-Component system (Material, Vitality, Spatial, etc.)

All game state flows through these validated types.

class babylon.models.SocialRole(*values)[source]

Bases: StrEnum

Class position in the world system.

Based on Marxist-Leninist-Maoist Third Worldist (MLM-TW) theory, classes are defined by their relationship to production AND their position in the imperial hierarchy.

Values:

CORE_BOURGEOISIE: Owns means of production in imperial core PERIPHERY_PROLETARIAT: Sells labor in exploited periphery LABOR_ARISTOCRACY: Core workers benefiting from imperial rent PETTY_BOURGEOISIE: Small owners, professionals, shopkeepers LUMPENPROLETARIAT: Outside formal economy, precarious existence COMPRADOR_BOURGEOISIE: Intermediary class in periphery, collaborates with imperial core INTERNAL_PROLETARIAT: Core workers outside LA (precariat, unemployed, incarcerated) CARCERAL_ENFORCER: Guards, cops, prison staff (repressive apparatus)

Terminal Crisis Dynamics (ai/terminal-crisis-dynamics.md):

When peripheral extraction fails and super-wages deplete, the Labor Aristocracy decomposes into CARCERAL_ENFORCER (30%) and INTERNAL_PROLETARIAT (70%). This models the carceral turn from productive to coercive labor.

CORE_BOURGEOISIE = 'core_bourgeoisie'
PERIPHERY_PROLETARIAT = 'periphery_proletariat'
LABOR_ARISTOCRACY = 'labor_aristocracy'
PETTY_BOURGEOISIE = 'petty_bourgeoisie'
LUMPENPROLETARIAT = 'lumpenproletariat'
COMPRADOR_BOURGEOISIE = 'comprador_bourgeoisie'
INTERNAL_PROLETARIAT = 'internal_proletariat'
CARCERAL_ENFORCER = 'carceral_enforcer'
class babylon.models.EdgeType(*values)[source]

Bases: StrEnum

Nature of relationships between entities.

These are the fundamental relationship types that form edges in the simulation’s NetworkX graph.

Values:

EXPLOITATION: Value extraction (imperial rent flows along these edges) SOLIDARITY: Mutual support and class consciousness REPRESSION: State violence directed at a class COMPETITION: Market rivalry between entities TRIBUTE: Value flow from periphery comprador to core (comprador keeps cut) WAGES: Core bourgeoisie paying core workers (super-wages from imperial rent) CLIENT_STATE: Imperial subsidy to maintain client state stability TENANCY: Occupant -> Territory relationship (Sprint 3.5.1) ADJACENCY: Territory -> Territory spatial connectivity (Sprint 3.5.1) TRANSACTIONAL: Service-for-support exchange (org-community, Feature 032) SOLIDARISTIC: Deep mutual commitment (org-community, Feature 032) ANTAGONISTIC: Manufactured conflict between orgs (Feature 039)

EXPLOITATION = 'exploitation'
SOLIDARITY = 'solidarity'
REPRESSION = 'repression'
COMPETITION = 'competition'
TRIBUTE = 'tribute'
WAGES = 'wages'
CLIENT_STATE = 'client_state'
TENANCY = 'tenancy'
ADJACENCY = 'adjacency'
MEMBERSHIP = 'membership'
RECRUITMENT = 'recruitment'
EMPLOYMENT = 'employment'
COMMAND = 'command'
PRESENCE = 'presence'
TRANSACTIONAL = 'transactional'
SOLIDARISTIC = 'solidaristic'
ANTAGONISTIC = 'antagonistic'
TARGETS = 'targets'
OWNED_BY = 'owned_by'
JURISDICTION = 'jurisdiction'
HOUSES = 'houses'
CLAIMS = 'claims'
INFLUENCES = 'influences'
ADMINISTERS = 'administers'
class babylon.models.IntensityLevel(*values)[source]

Bases: StrEnum

Intensity scale for contradictions and tensions.

Contradictions exist on a spectrum from dormant (latent potential) to critical (imminent rupture). This enum provides discrete levels for game mechanics while the underlying simulation may use continuous float values.

Values:

DORMANT: Contradiction exists but not yet manifest LOW: Minor tensions, easily managed MEDIUM: Noticeable conflict, requires attention HIGH: Serious crisis, intervention needed CRITICAL: Rupture imminent, phase transition likely

DORMANT = 'dormant'
LOW = 'low'
MEDIUM = 'medium'
HIGH = 'high'
CRITICAL = 'critical'
class babylon.models.ResolutionType(*values)[source]

Bases: StrEnum

How contradictions can resolve.

Based on dialectical materialism, contradictions resolve through one of three mechanisms. The resolution type determines what happens to the system after a contradiction reaches critical intensity.

Values:

SYNTHESIS: Dialectical resolution - opposites unite at higher level RUPTURE: Revolutionary break - system undergoes fundamental change SUPPRESSION: Forced dormancy - contradiction remains but is contained

SYNTHESIS = 'synthesis'
RUPTURE = 'rupture'
SUPPRESSION = 'suppression'
class babylon.models.SimulationConfig(**data)[source]

Bases: BaseModel

Immutable per-run settings for the simulation engine.

Game-balance coefficients live in GameDefines (read via services.defines); this model only carries run-scoped settings that are not part of the moddable coefficient surface. The config is frozen to preserve determinism during a run.

Parameters:

rng_seed (int)

rng_seed

Per-run RNG seed for byte-identical action replays (Constitution III.7). Threaded from the GameSession by the web bridge and serialized into the persisted run configuration.

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

rng_seed: int
class babylon.models.ScenarioConfig(**data)[source]

Bases: BaseModel

Configuration for multiverse scenario injection.

ScenarioConfig defines modifiers that transform a base WorldState and SimulationConfig into a specific counterfactual scenario. This enables deterministic exploration of parameter space without random sampling.

The model is frozen (immutable) to ensure scenarios remain constant throughout simulation runs.

Parameters:
  • name (str)

  • superwage_multiplier (float)

  • solidarity_index (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • repression_capacity (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

name

Human-readable scenario identifier, must be unique within a multiverse run. Format: “{SWLevel}_{SolidarityLevel}_{RepressionLevel}”

superwage_multiplier

Multiplier for extraction_efficiency in SimulationConfig. Default 1.0 (no change). Range: [0, inf). - 0.3 = Low superwage (periphery retains more value) - 1.5 = High superwage (aggressive extraction) Theory: “Superwage” refers to core worker wages above value produced, subsidized by imperial rent extraction.

solidarity_index

Base strength for SOLIDARITY edges in topology. Default 0.5. Constrained to [0, 1] via Coefficient type. - 0.2 = Low solidarity (atomized workers) - 0.8 = High solidarity (strong worker networks)

repression_capacity

State violence capacity modifier. Updates repression_faced on entities and repression_level in config. Default 0.5. Constrained to [0, 1] via Coefficient type. - 0.2 = Low repression (weak state) - 0.8 = High repression (police state)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
superwage_multiplier: float
solidarity_index: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
repression_capacity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
class babylon.models.WorldState(**data)[source]

Bases: BaseModel

Immutable snapshot of the simulation at a specific tick.

WorldState follows the Data/Logic separation principle: - State holds WHAT exists (pure data) - Engine determines HOW it transforms (pure logic)

This enables: - Determinism: Same state + same engine = same output - Replayability: Save initial state, replay entire history - Counterfactuals: Modify a parameter, run forward, compare - Testability: Feed state in, assert on state out

Parameters:
tick

Current turn number (0-indexed)

entities

Map of entity ID to SocialClass (the nodes)

territories

Map of territory ID to Territory (Layer 0 nodes)

relationships

List of Relationship edges (the edges)

event_log

Recent events for narrative/debugging (string format)

events

Structured simulation events for analysis (Sprint 3.1)

economy

Global economic state for dynamic balance (Sprint 3.4.4)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tick: int
entities: dict[str, SocialClass]
territories: dict[str, Territory]
relationships: list[Relationship]
event_log: list[str]
events: list[SimulationEvent]
economy: GlobalEconomy
state_finances: dict[str, StateFinance]
contradiction_frames: dict[str, ContradictionFrame]
opposition_states: dict[str, Any]
organizations: dict[str, Annotated[StateApparatus | Business | PoliticalFaction | CivilSocietyOrg, FieldInfo(annotation=NoneType, required=True, discriminator='org_type')]]
key_figures: dict[str, KeyFigure]
institutions: dict[str, Institution]
institution_relations: list[InstitutionOrgRelation]
industries: dict[str, IndustryHyperedge]
sovereigns: dict[str, Sovereign]
factions: dict[str, BalkanizationFaction]
to_graph()[source]

Convert state to a BabylonGraph for formula application.

The rustworkx-backed BabylonGraph (Amendment L) replaces the former NetworkX DiGraph; its nx-compat authoring surface keeps this method’s body and all downstream readers unchanged, and it satisfies GraphProtocol directly so systems no longer wrap per tick.

Nodes are entity/territory IDs with all fields as attributes. A _node_type marker distinguishes between node types: - _node_type=’social_class’ for SocialClass nodes - _node_type=’territory’ for Territory nodes

Edges are relationships with all Relationship fields as attributes.

Graph metadata (G.graph) contains: - economy: GlobalEconomy state (Sprint 3.4.4)

Return type:

BabylonGraph

Returns:

BabylonGraph with nodes and edges from this state.

Raises:

ValueError – If two relationships share a (source, target) pair with differing edge_types — BabylonGraph stores one edge per pair, so the collision would silently collapse last-writer-wins (Design B fail-loud).

Example:

G = state.to_graph()
for node_id, data in G.nodes(data=True):
    if data["_node_type"] == "social_class":
        data["wealth"] += 10  # Modify entity
new_state = WorldState.from_graph(G, tick=state.tick + 1)
classmethod from_graph(G, tick, event_log=None, events=None)[source]

Reconstruct WorldState from a BabylonGraph.

Parameters:
  • G (BabylonGraph) – Graph with node/edge data (BabylonGraph — the sole substrate since Amendment L closed the adapter seam)

  • tick (int) – The tick number for the new state

  • event_log (list[str] | None) – Optional event log to preserve (backward compatibility)

  • events (list[SimulationEvent] | None) – Optional structured events to include (Sprint 3.1)

Return type:

WorldState

Returns:

New WorldState with entities, territories, and relationships from graph.

Example

G = state.to_graph() # … modify graph … new_state = WorldState.from_graph(G, tick=state.tick + 1)

add_entity(entity)[source]

Return new state with entity added.

Parameters:

entity (SocialClass) – SocialClass to add

Return type:

WorldState

Returns:

New WorldState with the entity included.

Example

new_state = state.add_entity(worker)

add_territory(territory)[source]

Return new state with territory added.

Parameters:

territory (Territory) – Territory to add (Layer 0 node)

Return type:

WorldState

Returns:

New WorldState with the territory included.

Example

new_state = state.add_territory(university_district)

add_relationship(relationship)[source]

Return new state with relationship added.

Parameters:

relationship (Relationship) – Relationship edge to add

Return type:

WorldState

Returns:

New WorldState with the relationship included.

Example

new_state = state.add_relationship(exploitation_edge)

add_event(event)[source]

Return new state with event appended to log.

Parameters:

event (str) – Event description string

Return type:

WorldState

Returns:

New WorldState with event in log.

Example

new_state = state.add_event(“Worker crossed poverty threshold”)

property total_biocapacity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]

Global sum of territory biocapacity.

property total_consumption: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]

Global sum of consumption needs.

property overshoot_ratio: float

Global ecological overshoot ratio.

class babylon.models.SocialClass(**data)[source]

Bases: BaseModel

A social class in the world system.

The fundamental unit of the simulation. Classes are defined by their relationship to production and their position in the imperial hierarchy.

This model uses Sprint 1 constrained types for automatic validation: - Currency: [0, inf) for wealth, subsistence_threshold - IdeologicalProfile: Multi-dimensional consciousness model (Sprint 3.4.3) - Probability: [0, 1] for survival probabilities and organization/repression

Parameters:
  • id (str)

  • name (str)

  • role (SocialRole)

  • description (str)

  • wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • ideology (IdeologicalProfile)

  • p_acquiescence (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • p_revolution (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • subsistence_threshold (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • organization (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • repression_faced (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • effective_wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • unearned_increment (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • ppp_multiplier (float)

  • active (bool)

  • s_bio (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • s_class (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • subsistence_multiplier (float)

  • population (int)

  • inequality (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Gini coefficient measuring intra-class inequality', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • county_fips (str | None)

  • community_memberships (list[Any])

  • community_cost_modifier (float)

  • entitlement (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • volatility (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • fascist_alignment (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • aligned_faction_id (str | None)

id

Unique identifier matching pattern ^C[0-9]{3}$

name

Human-readable name for the class

role

Position in the world system (SocialRole enum)

description

Optional detailed description

wealth

Economic resources (Currency, default 10.0)

ideology

Multi-dimensional ideological profile (IdeologicalProfile)

p_acquiescence

P(S|A) - survival probability through acquiescence (Probability)

p_revolution

P(S|R) - survival probability through revolution (Probability)

subsistence_threshold

Minimum wealth for survival (Currency, default 5.0)

organization

Collective cohesion/class consciousness (Probability, default 0.1)

repression_faced

State violence directed at this class (Probability, default 0.5)

Legacy Compatibility:

If a float value is passed for ideology, it will be automatically converted to an IdeologicalProfile using from_legacy_ideology().

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True, 'str_strip_whitespace': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

classmethod unpack_components_and_convert_legacy(data)[source]

Unpack component objects and convert legacy ideology to IdeologicalProfile.

Return type:

Any

Parameters:

data (Any)

id: str
name: str
role: SocialRole
description: str
wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
ideology: IdeologicalProfile
p_acquiescence: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
p_revolution: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
subsistence_threshold: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
organization: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
repression_faced: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
effective_wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
unearned_increment: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
ppp_multiplier: float
active: bool
s_bio: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
s_class: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
subsistence_multiplier: float
population: int
inequality: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Gini coefficient measuring intra-class inequality', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
county_fips: str | None
community_memberships: list[Any]
community_cost_modifier: float
entitlement: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
volatility: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
fascist_alignment: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
aligned_faction_id: str | None
property consumption_needs: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]

Total consumption required per tick (Wealth-independent demand).

property economic: EconomicComponent

Return economic component view (computed, not live).

property survival: SurvivalComponent

Return survival component view (computed, not live).

property material_conditions: MaterialConditionsComponent

Return material conditions component view (computed, not live).

class babylon.models.Relationship(**data)[source]

Bases: BaseModel

A directed edge between two entities.

Represents flows of value, solidarity, or repression between classes. In Phase 1, the primary relationship is exploitation: value flows from the periphery worker (source) to the core owner (target).

This model uses Sprint 1 constrained types for automatic validation: - Currency: [0, inf) for value_flow - Intensity: [0, 1] for tension

Parameters:
  • source_id (str)

  • target_id (str)

  • edge_type (EdgeType)

  • value_flow (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • tension (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • description (str)

  • subsidy_cap (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • solidarity_strength (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • influence_level (float | None)

  • support_type (str | None)

  • control_level (float | None)

  • legal_status (str | None)

source_id

Origin entity ID (value/action flows FROM here)

target_id

Destination entity ID (value/action flows TO here)

edge_type

Nature of the relationship (EdgeType enum)

value_flow

Imperial rent or value transfer amount (Currency, default 0.0)

tension

Dialectical tension/contradiction intensity (Intensity, default 0.0)

description

Optional description of the relationship

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True, 'str_strip_whitespace': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

classmethod unpack_flow_component(data)[source]

Unpack flow component into flat fields if provided.

Return type:

Any

Parameters:

data (Any)

source_id: str
target_id: str
edge_type: EdgeType
value_flow: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
tension: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
description: str
subsidy_cap: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
solidarity_strength: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
influence_level: float | None
support_type: str | None
control_level: float | None
legal_status: str | None
validate_no_self_loop()[source]

Ensure entities cannot have a relationship with themselves.

Return type:

Relationship

property edge_tuple: tuple[str, str]

Return (source_id, target_id) tuple for NetworkX edge creation.

Usage:

G.add_edge(*relationship.edge_tuple, **relationship.edge_data)
property edge_data: dict[str, object]

Return edge attributes dict for the graph, excluding IDs.

exclude_none=True keeps the optional spec-070 fields (influence_level/support_type/control_level/ legal_status) out of every edge that doesn’t carry them — no pre-existing field is ever None, so all other payloads are byte-identical to the pre-A6 emission.

Usage:

G.add_edge(*relationship.edge_tuple, **relationship.edge_data)
property flow: FlowComponent

Return flow component view (computed, not live).

class babylon.models.IdeologicalProfile(**data)[source]

Bases: BaseModel

Multi-dimensional ideological state of a social class.

Sprint 3.4.3 (George Jackson Refactor): This model replaces the scalar ideology field with a multi-dimensional consciousness model.

The key insight: “Fascism is the defensive form of capitalism.” - Agitation + Solidarity -> Class Consciousness (Revolutionary Path) - Agitation + No Solidarity -> National Identity (Fascist Path)

Parameters:
  • class_consciousness (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Relationship to Capital: 0=False Consciousness, 1=Revolutionary', metadata=[Ge(ge=0.0), Le(le=1.0)])])

  • national_identity (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Relationship to State/Tribe: 0=Internationalist, 1=Nativist/Fascist', metadata=[Ge(ge=0.0), Le(le=1.0)])])

  • agitation (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Raw political energy from crisis (falling wages)', metadata=[Ge(ge=0.0)])])

class_consciousness

Relationship to Capital [0.0=False, 1.0=Revolutionary] How clearly the class understands its position relative to capital.

national_identity

Relationship to State/Tribe [0.0=Internationalist, 1.0=Fascist] How strongly the class identifies with nation/race over class.

agitation

Raw political energy from crisis [0.0, inf) Accumulated energy from falling wages, crisis conditions. Routes to either axis based on solidarity_pressure.

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class_consciousness: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Relationship to Capital: 0=False Consciousness, 1=Revolutionary', metadata=[Ge(ge=0.0), Le(le=1.0)])]
national_identity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Relationship to State/Tribe: 0=Internationalist, 1=Nativist/Fascist', metadata=[Ge(ge=0.0), Le(le=1.0)])]
agitation: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Raw political energy from crisis (falling wages)', metadata=[Ge(ge=0.0)])]
classmethod from_legacy_ideology(ideology_value)[source]

Convert legacy scalar ideology [-1, 1] to IdeologicalProfile.

Legacy mapping: - ideology=-1 (revolutionary) -> class_consciousness=1.0, national_identity=0.0 - ideology=0 (neutral) -> class_consciousness=0.5, national_identity=0.5 - ideology=+1 (reactionary) -> class_consciousness=0.0, national_identity=1.0

Parameters:

ideology_value (float) – Legacy ideology scalar in range [-1.0, 1.0]

Return type:

IdeologicalProfile

Returns:

IdeologicalProfile with mapped values

to_legacy_ideology()[source]

Convert IdeologicalProfile back to legacy scalar ideology [-1, 1].

This provides backward compatibility for systems still using the scalar ideology representation.

Return type:

float

Returns:

Legacy ideology scalar in range [-1.0, 1.0]

class babylon.models.GlobalEconomy(**data)[source]

Bases: BaseModel

System-wide economic state for dynamic balance mechanics.

The GlobalEconomy model tracks the “Gas Tank” (imperial rent pool) and the “Driver” parameters (wage rate, repression level) that the bourgeoisie can adjust based on pool levels and tension.

Parameters:
  • imperial_rent_pool (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • super_wage_rate (Annotated[float, Ge(ge=0.0), Le(le=1.0), AfterValidator(func=~babylon.kernel.math.quantize)])

  • repression_level (Annotated[float, Ge(ge=0.0), Le(le=1.0), AfterValidator(func=~babylon.kernel.math.quantize)])

imperial_rent_pool

Accumulated imperial rent available for redistribution. Fed by TRIBUTE inflows, depleted by WAGES and CLIENT_STATE outflows. Default: 100.0 Currency.

current_super_wage_rate

Dynamic wage rate for WAGES edges. Adjusts based on pool level and tension via decision heuristics. Range: [0.05, 0.35]. Default: 0.20 (20%).

current_repression_level

System-wide repression modifier. Blended with per-class repression_faced values. Increases during austerity/crisis periods. Range: [0.0, 1.0]. Default: 0.5.

Pool Flow Logic:

inflow = sum(tribute reaching Core Bourgeoisie after comprador cut) outflow = wages_paid + subsidy_paid delta = inflow - outflow new_pool = old_pool + delta

Decision Thresholds (Aggressive):

pool_ratio >= 0.7: PROSPERITY (can increase wages) pool_ratio < 0.3: AUSTERITY (cut wages or increase repression) pool_ratio < 0.1: CRISIS (emergency measures, emit event)

model_config: ClassVar[ConfigDict] = {'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

imperial_rent_pool: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
current_super_wage_rate: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
current_repression_level: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
class babylon.models.Effect(**data)[source]

Bases: BaseModel

A modification to game state.

Effects are the atoms of change - they modify single attributes on single targets by specific amounts. Every state change in the simulation should be expressible as one or more Effects.

Parameters:
  • target_id (str)

  • attribute (str)

  • operation (Literal['increase', 'decrease', 'set', 'multiply'])

  • magnitude (float)

  • description (str)

target_id

ID of the entity to modify

attribute

Name of the attribute to change

operation

How to modify the value

magnitude

Amount of change (interpretation depends on operation)

description

Human-readable explanation of why this effect occurs

target_id: str
attribute: str
operation: Literal['increase', 'decrease', 'set', 'multiply']
magnitude: float
description: str
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

apply_to(current_value)[source]

Calculate the new value after applying this effect.

Parameters:

current_value (float) – The current value of the attribute

Return type:

float

Returns:

The new value after the effect is applied

class babylon.models.ContradictionFrame(**data)[source]

Bases: BaseModel

The 2x2 contradiction matrix at a given scale and moment.

Models the principal and secondary contradictions for a specific scope.

Parameters:
principal: Contradiction
secondary: Contradiction
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class babylon.models.Contradiction(**data)[source]

Bases: BaseModel

A structural contradiction at a specific scale.

Instead of hardcoding the fractal, this uses a dynamic aspect mapping.

Parameters:
  • id (str)

  • type (ContradictionType)

  • aspect_a (str)

  • aspect_b (str)

  • principal_aspect (Literal['a', 'b'])

  • identity (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • intensity (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • aspect_balance (float)

  • form_of_struggle (EdgeMode)

  • is_antagonistic (bool)

id: str
type: ContradictionType
aspect_a: str
aspect_b: str
principal_aspect: Literal['a', 'b']
identity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
intensity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Contradiction intensity from dormant (0) to rupture (1)', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
aspect_balance: float
form_of_struggle: EdgeMode
is_antagonistic: bool
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class babylon.models.Trigger(**data)[source]

Bases: BaseModel

A condition that can trigger game events.

Triggers define when events should occur based on game state. They can have multiple conditions that must all be met (AND logic) or any one met (OR logic).

Parameters:
id

Unique identifier

description

Human-readable description

trigger_type

Category of trigger (economic, political, social, etc.)

conditions

List of conditions to evaluate

logic

How to combine conditions (all must pass or any must pass)

parameters

Optional parameters for condition evaluation

cooldown_turns

Minimum turns between activations (0 = no cooldown)

last_triggered_turn

Turn when this was last triggered

id: str
description: str
trigger_type: str | None
conditions: list[TriggerCondition]
logic: Literal['all', 'any']
parameters: dict[str, Any]
cooldown_turns: int
last_triggered_turn: int | None
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

evaluate(game_state, current_turn=0)[source]

Evaluate if the trigger condition is met.

Parameters:
  • game_state (dict[str, Any]) – The current game state to evaluate against

  • current_turn (int) – The current turn number (for cooldown checking)

Return type:

bool

Returns:

True if the trigger condition is met, False otherwise

mark_triggered(current_turn)[source]

Return a new Trigger with last_triggered_turn set to current_turn.

Per Constitution III.7 (Determinism), Trigger is a frozen Pydantic model; this method returns a new instance via model_copy(update=...) rather than mutating in place. Callers MUST replace the original trigger in their containing collection with the returned instance.

Parameters:

current_turn (int) – The current turn number.

Return type:

Trigger

Returns:

A new Trigger with last_triggered_turn=current_turn.

class babylon.models.TriggerCondition(**data)[source]

Bases: BaseModel

A single condition that can be evaluated against game state.

Conditions specify what to check, how to compare, and what threshold to use. Multiple conditions can be combined in a Trigger.

Parameters:
  • path (str)

  • operator (Literal['>=', '<=', '>', '<', '==', '!='])

  • threshold (float)

  • description (str)

path

Dot-notation path to the value in game state (e.g., “economy.gini_coefficient”)

operator

Comparison operator

threshold

Value to compare against

description

Human-readable explanation

path: str
operator: Literal['>=', '<=', '>', '<', '==', '!=']
threshold: float
description: str
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

evaluate(game_state)[source]

Evaluate this condition against the game state.

Parameters:

game_state (dict[str, Any]) – The current game state dictionary

Return type:

bool

Returns:

True if the condition is met, False otherwise

class babylon.models.Component(*args, **kwargs)[source]

Bases: Protocol

Protocol defining the interface for all component types.

All components in the Babylon simulation must implement this protocol. The protocol requires a component_type property that returns a string identifier for the component type.

This protocol is runtime-checkable, meaning you can use isinstance() to verify that an object implements the Component interface.

Example

>>> class MyComponent(BaseModel):
...     model_config = ConfigDict(frozen=True)
...     @property
...     def component_type(self) -> str:
...         return "my_component"
...
>>> instance = MyComponent()
>>> isinstance(instance, Component)
True
property component_type: str

Return the component type identifier.

Returns:

A string identifying the type of this component. For example: “material”, “vitality”, “spatial”, etc.

__init__(*args, **kwargs)
class babylon.models.MaterialComponent(**data)[source]

Bases: BaseModel

Material conditions of an entity.

Tracks the economic and material state of an entity including: - Accumulated wealth (Currency) - Available resources (Currency) - Control over means of production (Probability)

All values use constrained types for automatic validation: - wealth, resources: Currency [0, inf) - means_of_production: Probability [0, 1]

This component is immutable (frozen) to ensure state integrity.

Parameters:
  • wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • resources (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • means_of_production (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

wealth

Accumulated economic resources (default: 10.0)

resources

Available material resources (default: 0.0)

means_of_production

Control over productive apparatus [0, 1] (default: 0.0)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
resources: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
means_of_production: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
property component_type: str

Return the component type identifier.

Returns:

The string ‘material’ identifying this component type.

class babylon.models.VitalityComponent(**data)[source]

Bases: BaseModel

Population and survival needs of an entity.

Tracks the demographic and subsistence state of an entity: - Population size (Currency) - Minimum resources required for survival (Currency)

All values use constrained types for automatic validation: - population, subsistence_needs: Currency [0, inf)

This component is immutable (frozen) to ensure state integrity.

Parameters:
  • population (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • subsistence_needs (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

population

Size of the population (default: 1.0)

subsistence_needs

Resources needed for survival (default: 5.0)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

population: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
subsistence_needs: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
property component_type: str

Return the component type identifier.

Returns:

The string ‘vitality’ identifying this component type.

class babylon.models.SpatialComponent(**data)[source]

Bases: BaseModel

Location and mobility of an entity.

Tracks the spatial state of an entity: - Geographic/topological location identifier (string) - Ability to relocate (Probability)

All numeric values use constrained types for automatic validation: - mobility: Probability [0, 1]

This component is immutable (frozen) to ensure state integrity.

Parameters:
  • location_id (str)

  • mobility (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

location_id

Geographic or topological location identifier (default: “”)

mobility

Ability to relocate [0=immobile, 1=fully mobile] (default: 0.5)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

location_id: str
mobility: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
property component_type: str

Return the component type identifier.

Returns:

The string ‘spatial’ identifying this component type.

class babylon.models.OrganizationComponent(**data)[source]

Bases: BaseModel

Organizational capacity of an entity.

Tracks the organizational state of an entity: - Internal unity and coordination (Probability) - Quality of organizational leadership (Probability)

All values use constrained types for automatic validation: - cohesion: Probability [0, 1] - cadre_level: Probability [0, 1]

This component is immutable (frozen) to ensure state integrity.

Parameters:
  • cohesion (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • cadre_level (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

cohesion

Internal unity and coordination [0=atomized, 1=unified] (default: 0.1)

cadre_level

Quality of organizational leadership [0=none, 1=elite] (default: 0.0)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

cohesion: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
cadre_level: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
property component_type: str

Return the component type identifier.

Returns:

The string ‘organization’ identifying this component type.

class babylon.models.TopologySnapshot(**data)[source]

Bases: BaseModel

Metrics snapshot of the solidarity subgraph at a specific tick.

Captures the topological state of SOLIDARITY edges in the social graph, enabling detection of phase transitions from atomized (gaseous) to condensed (liquid) movement states.

Parameters:
  • tick (int)

  • num_components (int)

  • max_component_size (int)

  • total_nodes (int)

  • percolation_ratio (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • potential_liquidity (int)

  • actual_liquidity (int)

  • cadre_density (float)

  • is_resilient (bool | None)

tick

Simulation tick when snapshot was taken

num_components

Number of disconnected subgraphs (solidarity cells)

max_component_size

Size of the largest connected component (L_max)

total_nodes

Total number of social_class nodes (N)

percolation_ratio

L_max / N, measures giant component dominance

potential_liquidity

Count of SOLIDARITY edges > 0.1 (sympathizers)

actual_liquidity

Count of SOLIDARITY edges > 0.5 (cadre)

is_resilient

Whether movement survives 20% purge (optional)

Interpretation (4-Phase Model):
  • percolation_ratio < 0.1: Gaseous (atomized, no coordination)

  • 0.1 <= percolation_ratio < 0.5: Transitional (emerging structure)

  • percolation_ratio >= 0.5 AND cadre_density < 0.5: Liquid (mass movement)

  • percolation_ratio >= 0.5 AND cadre_density >= 0.5: Solid (vanguard party)

  • potential >> actual: Broad but brittle (lacks cadre discipline)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tick: int
num_components: int
max_component_size: int
total_nodes: int
percolation_ratio: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
potential_liquidity: int
actual_liquidity: int
cadre_density: float
is_resilient: bool | None
class babylon.models.ResilienceResult(**data)[source]

Bases: BaseModel

Result of purge simulation (Sword of Damocles test).

Tests whether the solidarity network survives targeted removal of a percentage of nodes. A resilient network maintains its giant component after losing key members.

Parameters:
  • is_resilient (bool)

  • original_max_component (int)

  • post_purge_max_component (int)

  • removal_rate (float)

  • survival_threshold (float)

  • seed (int | None)

is_resilient

True if post-purge L_max > threshold of original L_max

original_max_component

Size of L_max before purge

post_purge_max_component

Size of L_max after purge

removal_rate

Fraction of nodes removed (e.g., 0.2 = 20%)

survival_threshold

Required fraction of original L_max to survive

seed

RNG seed for reproducibility (None if random)

Interpretation:
  • is_resilient=True: Network can survive targeted repression

  • is_resilient=False: “Sword of Damocles” - purge would destroy movement

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

is_resilient: bool
original_max_component: int
post_purge_max_component: int
removal_rate: float
survival_threshold: float
seed: int | None
class babylon.models.EntityMetrics(**data)[source]

Bases: BaseModel

Metrics snapshot for a single entity at a specific tick.

Captures wealth, consciousness, and survival probabilities for analysis and visualization.

Parameters:
  • wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • consciousness (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • national_identity (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • agitation (float)

  • p_acquiescence (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • p_revolution (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • organization (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • population (int)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
consciousness: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
national_identity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
agitation: float
p_acquiescence: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
p_revolution: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
organization: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
population: int
class babylon.models.EdgeMetrics(**data)[source]

Bases: BaseModel

Metrics snapshot for relationship edges at a specific tick.

Captures tension, value flows, and solidarity strength for analysis and visualization.

Parameters:
  • exploitation_tension (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • exploitation_rent (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • tribute_flow (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • wages_paid (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • solidarity_strength (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

exploitation_tension: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
exploitation_rent: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
tribute_flow: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
wages_paid: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
solidarity_strength: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
class babylon.models.TickMetrics(**data)[source]

Bases: BaseModel

Complete metrics snapshot for a single simulation tick.

Aggregates entity and edge metrics for comprehensive tick analysis.

Parameters:
  • tick (int)

  • p_w (EntityMetrics | None)

  • p_c (EntityMetrics | None)

  • c_b (EntityMetrics | None)

  • c_w (EntityMetrics | None)

  • edges (EdgeMetrics)

  • imperial_rent_pool (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • global_tension (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • current_super_wage_rate (float)

  • current_repression_level (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • pool_ratio (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • topology (TopologySummary | None)

  • consciousness_gap (float)

  • wealth_gap (float)

  • overshoot_ratio (float)

  • total_biocapacity (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • total_consumption (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tick: int
p_w: EntityMetrics | None
p_c: EntityMetrics | None
c_b: EntityMetrics | None
c_w: EntityMetrics | None
edges: EdgeMetrics
imperial_rent_pool: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
global_tension: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
current_super_wage_rate: float
current_repression_level: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
pool_ratio: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
topology: TopologySummary | None
consciousness_gap: float
wealth_gap: float
overshoot_ratio: float
total_biocapacity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
total_consumption: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
class babylon.models.SweepSummary(**data)[source]

Bases: BaseModel

Summary statistics for a completed simulation run.

Aggregates metrics across all ticks for parameter sweep analysis.

Parameters:
  • ticks_survived (int)

  • outcome (Literal['SURVIVED', 'DIED', 'ERROR'])

  • final_p_w_wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • final_p_c_wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • final_c_b_wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • final_c_w_wealth (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • max_tension (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • crossover_tick (int | None)

  • cumulative_rent (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • peak_p_w_consciousness (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

  • peak_c_w_consciousness (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)])

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

ticks_survived: int
outcome: Literal['SURVIVED', 'DIED', 'ERROR']
final_p_w_wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
final_p_c_wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
final_c_b_wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
final_c_w_wealth: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
max_tension: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
crossover_tick: int | None
cumulative_rent: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]
peak_p_w_consciousness: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
peak_c_w_consciousness: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
class babylon.models.GraphNode(**data)[source]

Bases: BaseModel

Type-safe graph node representation.

Frozen Pydantic model for node data at the protocol boundary. Adapters convert to/from their internal representation.

Parameters:
id

Unique node identifier.

node_type

Discriminator for polymorphism (e.g., ‘social_class’, ‘territory’).

attributes

Type-specific attributes stored as dict.

Example

>>> node = GraphNode(id="C001", node_type="social_class", attributes={"wealth": 100.0})
>>> node.wealth
100.0
model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

id: str
node_type: str
attributes: dict[str, Any]
get_attr(key, default=None)[source]

Get attribute with default.

Parameters:
  • key (str) – Attribute name to retrieve.

  • default (Any) – Value to return if attribute not present.

Return type:

Any

Returns:

The attribute value or default.

property wealth: float

Convenience accessor for wealth attribute.

Returns:

Wealth value or 0.0 if not present.

class babylon.models.GraphEdge(**data)[source]

Bases: BaseModel

Type-safe graph edge representation.

Frozen Pydantic model for edge data at the protocol boundary. Adapters convert to/from their internal representation.

Parameters:
source_id

Origin node ID.

target_id

Destination node ID.

edge_type

Edge category (e.g., ‘SOLIDARITY’, ‘EXPLOITATION’).

weight

Generic weight (default 1.0).

attributes

Type-specific attributes stored as dict.

Example

>>> edge = GraphEdge(source_id="C001", target_id="C002", edge_type="SOLIDARITY")
>>> edge.weight
1.0
model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

source_id: str
target_id: str
edge_type: str
weight: float
attributes: dict[str, Any]
property tension: float

Convenience accessor for tension attribute.

Returns:

Tension value or 0.0 if not present.

property value_flow: float

Convenience accessor for value_flow attribute.

Returns:

Value flow or 0.0 if not present.

class babylon.models.EdgeFilter(**data)[source]

Bases: BaseModel

Filter specification for edge traversal.

Used to select which edges to traverse during graph operations. All fields are optional - None means no filter (match all).

Parameters:
  • edge_types (set[str] | None)

  • min_weight (float | None)

  • max_weight (float | None)

edge_types

Set of edge types to include (None = all types).

min_weight

Minimum weight threshold (inclusive).

max_weight

Maximum weight threshold (inclusive).

Example

>>> f = EdgeFilter(edge_types={"SOLIDARITY"}, min_weight=0.5)
>>> f.edge_types
{'SOLIDARITY'}
model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

edge_types: set[str] | None
min_weight: float | None
max_weight: float | None
class babylon.models.NodeFilter(**data)[source]

Bases: BaseModel

Filter specification for node inclusion.

Used to select which nodes to include during graph operations. All fields are optional - None means no filter (match all).

Parameters:
node_types

Set of node types to include (None = all types).

attribute_predicates

Dict of attribute equality filters.

Example

>>> f = NodeFilter(node_types={"social_class"})
>>> f.node_types
{'social_class'}
model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

node_types: set[str] | None
attribute_predicates: dict[str, Any] | None
class babylon.models.TraversalQuery(**data)[source]

Bases: BaseModel

Generic traversal query specification.

Specifies what traversal to execute and what to collect. This is the generic hook for complex operations like percolation analysis, pathfinding, and component detection.

Parameters:
  • query_type (Literal['bfs', 'dfs', 'shortest_path', 'connected_components', 'percolation', 'reachability'])

  • start_nodes (list[str] | None)

  • target_nodes (list[str] | None)

  • edge_filter (EdgeFilter | None)

  • node_filter (NodeFilter | None)

  • max_depth (int | None)

  • collect (list[str])

query_type

Type of traversal algorithm to use.

start_nodes

Starting node IDs (None = all nodes).

target_nodes

Target node IDs (for shortest_path, reachability).

edge_filter

Filter which edges to traverse.

node_filter

Filter which nodes to include.

max_depth

Maximum traversal depth.

collect

What to include in result.

Example

>>> query = TraversalQuery(query_type="bfs", start_nodes=["C001"])
>>> query.query_type
'bfs'
model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

query_type: Literal['bfs', 'dfs', 'shortest_path', 'connected_components', 'percolation', 'reachability']
start_nodes: list[str] | None
target_nodes: list[str] | None
edge_filter: EdgeFilter | None
node_filter: NodeFilter | None
max_depth: int | None
collect: list[str]
class babylon.models.TraversalResult(**data)[source]

Bases: BaseModel

Result of traversal query execution.

Contains all data collected during traversal based on query.collect.

Parameters:
nodes

Node IDs in traversal result.

edges

Edge tuples (source, target, type) in result.

paths

Paths found (for shortest_path queries).

components

Connected components (for component queries).

component_sizes

Sizes of connected components (sorted descending).

metadata

Query-specific metadata.

Example

>>> result = TraversalResult(component_sizes=[10, 5, 3])
>>> result.largest_component_size
10
model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

nodes: list[str]
edges: list[tuple[str, str, str]]
paths: list[list[str]]
components: list[list[str]]
component_sizes: list[int]
metadata: dict[str, Any]
property largest_component_size: int

Size of the largest (giant) component.

Returns:

Size of first component or 0 if no components.

property percolation_ratio: float

Fraction of nodes in the largest component.

This is the key metric for phase transition detection. A ratio near 1.0 indicates full percolation (connectivity).

Returns:

Ratio of largest_component_size to total nodes, or 0.0 if empty.

babylon.models.role_to_entity_id(role)[source]

Convert a SocialRole enum to its canonical entity ID.

Parameters:

role (SocialRole) – SocialRole enum value

Return type:

str

Returns:

Entity ID string (e.g., “C001”)

Raises:

KeyError – If the role has no entity ID mapping (e.g., LUMPENPROLETARIAT)

Example

>>> role_to_entity_id(SocialRole.PERIPHERY_PROLETARIAT)
'C001'
babylon.models.entity_id_to_role(entity_id)[source]

Convert an entity ID to its SocialRole enum.

Parameters:

entity_id (str) – Entity ID string (e.g., “C001”)

Return type:

SocialRole

Returns:

SocialRole enum value

Raises:

KeyError – If the entity ID is not recognized

Example

>>> entity_id_to_role("C001")
<SocialRole.PERIPHERY_PROLETARIAT: 'periphery_proletariat'>
babylon.models.get_slot_name(entity_id)[source]

Get the short slot name for an entity ID.

Slot names are used for CSV column prefixes and metrics keys.

Parameters:

entity_id (str) – Entity ID string (e.g., “C001”)

Return type:

str

Returns:

Short slot name (e.g., “p_w”)

Raises:

KeyError – If the entity ID is not recognized

Example

>>> get_slot_name("C001")
'p_w'
class babylon.models.HexState(**data)[source]

Bases: BaseModel

Immutable geographic cell snapshot.

Hexes are the invariant substrate - they don’t change during simulation. For MVP, HexState contains only the H3 index. Future versions may add physical properties (terrain, resources).

Parameters:

h3_index (str)

h3_index

H3 cell index (15-char hex string, resolution 5).

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

h3_index: str
classmethod validate_h3_index(v)[source]

Validate H3 index is 15-char lowercase hex.

Return type:

str

Parameters:

v (str)

class babylon.models.EdgeState(**data)[source]

Bases: BaseModel

Relationship snapshot between entities at a specific tick.

Parameters:
source_id

ID of the source entity.

target_id

ID of the target entity.

edge_type

Relationship type.

weight

Edge weight (default 1.0).

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

source_id: str
target_id: str
edge_type: SnapshotEdgeType
weight: float
class babylon.models.TerritoryState(**data)[source]

Bases: BaseModel

Territory state snapshot at a specific tick.

This is the GUI-facing representation of a territory.

Parameters:
territory_id

Unique identifier (FIPS code for counties).

controlling_polity

Current controller (equals territory_id for MVP).

hex_claims

Set of H3 indices this territory claims.

tick

Tick number when this snapshot was taken.

profit_rate

Current profit rate, range [0.0, 1.0].

equilibrium_r

Territory-specific equilibrium (= initial_r at hydration).

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

territory_id: str
controlling_polity: str
hex_claims: frozenset[str]
tick: int
profit_rate: float
equilibrium_r: float
tensor_year: int | None
classmethod validate_territory_id(v)[source]

Validate territory_id is a 5-digit FIPS code.

Return type:

str

Parameters:

v (str)

classmethod convert_hex_claims(v)[source]

Convert hex_claims to frozenset for immutability.

Return type:

frozenset[str]

Parameters:

v (set[str] | frozenset[str] | list[str])

validate_hex_claims_patterns()[source]

Validate all H3 indices in hex_claims match pattern.

Return type:

TerritoryState

classmethod with_clamped_profit_rate(territory_id, controlling_polity, hex_claims, tick, profit_rate, equilibrium_r, tensor_year=None)[source]

Create TerritoryState with profit_rate clamped to [0.0, 1.0].

If profit_rate is outside valid range, it is clamped and a warning is logged.

Parameters:
  • territory_id (str) – FIPS code.

  • controlling_polity (str) – Controller ID.

  • hex_claims (set[str] | frozenset[str]) – Set of H3 indices.

  • tick (int) – Current tick.

  • profit_rate (float) – Computed profit rate (may be out of range).

  • equilibrium_r (float) – Territory-specific equilibrium.

  • tensor_year (int | None) – Year for tensor lookup (may differ from tick). None if no tensor data.

Return type:

TerritoryState

Returns:

TerritoryState with clamped profit_rate.

class babylon.models.SimulationSnapshot(**data)[source]

Bases: BaseModel

Complete simulation state at a specific tick.

This is the top-level container returned by get_snapshot().

Parameters:
tick

Current tick number.

territories

Map of territory_id to TerritoryState.

hexes

Map of h3_index to HexState (invariant substrate).

edges

List of EdgeState relationships (empty for MVP).

tensor_registry

Optional reference to TensorRegistry for cached tensor data access without database queries.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tick: int
territories: dict[str, TerritoryState]
hexes: dict[str, HexState]
edges: list[EdgeState]
tensor_registry: Any
validate_hex_references()[source]

Validate all hex_claims reference existing hexes.

Return type:

SimulationSnapshot

class babylon.models.SnapshotEdgeType(*values)[source]

Bases: StrEnum

Edge types for simulation snapshots.

Maps to constitution I.6 edge modes.

ADJACENCY = 'ADJACENCY'
EXTRACTION = 'EXTRACTION'
SOLIDARITY = 'SOLIDARITY'
ANTAGONISTIC = 'ANTAGONISTIC'
class babylon.models.CommunityType(*values)[source]

Bases: StrEnum

Community types for hypergraph membership (Constitution II.7).

Three structurally distinct categories — NOT a spectrum.

Category 1 — Contradiction Pairs (both sides real hyperedges):

SETTLER: Settler nation (hegemonic). Institutions: HOAs, police unions, border militias. NEW_AFRIKAN: New Afrikan / Black internal nation (marginalized) FIRST_NATIONS: Indigenous / First Nations peoples (marginalized) CHICANO: Chicano / Mexican-American nation (marginalized) PATRIARCHAL: Patriarchal order (hegemonic). Institutions: gendered wage systems, family structure. WOMEN: Women — reproductive labor allocation (marginalized) TRANS: Transgender / gender non-conforming (marginalized)

Category 2 — Institutional Exclusion (only marginalized side):

DISABLED: Disabled community. Built environment assumes able-bodiedness. QUEER: Queer / LGBQ. Institutional heteronormativity. UNDOCUMENTED: Undocumented. Legal exclusion from protections. INCARCERATED: Incarcerated. Carceral system, civil death.

Category 3 — Lifecycle Phases (D-P-D’ Circuit):

YOUTH: D phase. Pre-productive, dependent, receives socialization. ADULT: P phase. Sells labor-power. Where C-M-C and M-C-M’ operate. ELDER: D’ phase. Post-productive. Legitimation bargain (pensions, Social Security).

SETTLER = 'settler'
PATRIARCHAL = 'patriarchal'
NEW_AFRIKAN = 'new_afrikan'
FIRST_NATIONS = 'first_nations'
CHICANO = 'chicano'
WOMEN = 'women'
TRANS = 'trans'
DISABLED = 'disabled'
QUEER = 'queer'
UNDOCUMENTED = 'undocumented'
INCARCERATED = 'incarcerated'
YOUTH = 'youth'
ADULT = 'adult'
ELDER = 'elder'
class babylon.models.LegalStatus(*values)[source]

Bases: StrEnum

Legal designation status for community-level state repression.

Hypergraph Community Layer (Feature 022): Escalation is strictly one-way for state action. De-escalation requires political struggle (player action). Each level increases the threat multiplier applied to community members.

Values:

LEGAL: Normal status, minimal state attention (multiplier 0.1) SURVEILLED: Active monitoring (multiplier 0.5) DESIGNATED_EXTREMIST: Formal extremist designation (multiplier 1.0) DESIGNATED_TERRORIST: Formal terrorist designation (multiplier 2.0) CRIMINALIZED: Membership itself criminalized (multiplier 3.0)

LEGAL = 'legal'
SURVEILLED = 'surveilled'
DESIGNATED_EXTREMIST = 'designated_extremist'
DESIGNATED_TERRORIST = 'designated_terrorist'
CRIMINALIZED = 'criminalized'
class babylon.models.MembershipRole(*values)[source]

Bases: StrEnum

Agent integration level within a community.

Hypergraph Community Layer (Feature 022): Determines membership strength weight and visibility profile for threat score computation.

Values:

CORE_ORGANIZER: Infrastructure maintainers, visible leaders (weight 1.0) ACTIVE: Regular participants, known within community (weight 0.7) PARTICIPANT: Occasional engagement (weight 0.4) PERIPHERAL: Marginal connection (weight 0.2) SYMPATHIZER: External ally, not legible as member (weight 0.1)

CORE_ORGANIZER = 'core_organizer'
ACTIVE = 'active'
PARTICIPANT = 'participant'
PERIPHERAL = 'peripheral'
SYMPATHIZER = 'sympathizer'
class babylon.models.CommunityState(**data)[source]

Bases: BaseModel

State of a community, independent of its members.

Each community has collective attributes tracking state attention, internal cohesion, organizational infrastructure, and material modifiers applied to all members.

Parameters:
  • community_type (CommunityType) – Identity of this community.

  • heat (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – State attention/surveillance intensity [0, 1].

  • legal_status (LegalStatus) – Current legal designation (one-way escalation).

  • cohesion (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Internal trust and mutual aid effectiveness [0, 1].

  • infrastructure (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Organizational capacity (meeting spaces, comms) [0, 1].

  • visibility (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Community legibility to state surveillance [0, 1].

  • reproduction_cost_modifier (float) – Multiplier on V_reproduction for members.

  • rent_access_modifier (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Multiplier on imperial rent received by members.

  • category (HyperedgeCategory)

  • consciousness (TernaryConsciousness)

  • education_pressure (float)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

community_type: CommunityType
category: HyperedgeCategory
heat: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
legal_status: LegalStatus
cohesion: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
infrastructure: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
visibility: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
reproduction_cost_modifier: float
rent_access_modifier: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
consciousness: TernaryConsciousness
education_pressure: float
property infiltration_resistance: float

Community resistance to state infiltration.

Formula: CI * 0.6 + cohesion * 0.3 + CI * cohesion * 0.1

Returns:

Resistance score in [0.0, 1.0].

property is_cross_class_bridge: bool

Whether this community can span contradiction axes.

Only INSTITUTIONAL_EXCLUSION communities bridge across axes because their members can come from both hegemonic and marginalized sides.

Returns:

True if the community is an institutional exclusion type.

class babylon.models.CommunityMembership(**data)[source]

Bases: BaseModel

An agent’s membership in a community.

Represents the relationship between an individual agent and a community hyperedge. Each membership has a role determining integration level and a visibility determining legibility to state.

Parameters:
  • agent_id (str) – Identifier of the member agent.

  • community_type (CommunityType) – Which community this membership is in.

  • role (MembershipRole) – Integration level within the community.

  • strength (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Membership weight [0, 1], derived from role default.

  • visibility (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Base legibility to state [0, 1].

  • overt (bool) – Publicly identified — overrides visibility to 1.0.

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

agent_id: str
community_type: CommunityType
role: MembershipRole
strength: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Formula parameter in range [0, 1]', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
visibility: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
overt: bool
property effective_visibility: float

Effective visibility accounting for overt flag.

Returns:

1.0 if overt, otherwise the base visibility value.

class babylon.models.HyperedgeCategory(*values)[source]

Bases: StrEnum

Structural category for community hyperedges (Feature 029, Constitution II.7).

Three qualitatively distinct categories with different material bases, relationships to oppression, and modeling requirements.

Values:
CONTRADICTION_PAIR: Both hegemonic and marginalized sides exist as real

hyperedges with extraction flows between them.

INSTITUTIONAL_EXCLUSION: Only marginalized side exists. Oppression flows

through institutional defaults, not a paired oppressor community.

LIFECYCLE_PHASE: Temporal positions in D-P-D’ intergenerational lifecycle.

Universal, temporally permeable, defined by relationship to production.

ECONOMIC_SECTOR: Industry sectors represented by 2-digit NAICS codes. Used

for tracking economic metabolism, business coordination, and profit equalization.

CONTRADICTION_PAIR = 'contradiction_pair'
INSTITUTIONAL_EXCLUSION = 'institutional_exclusion'
LIFECYCLE_PHASE = 'lifecycle_phase'
ECONOMIC_SECTOR = 'economic_sector'
class babylon.models.ConsciousnessTendency(*values)[source]

Bases: StrEnum

Dominant ideological tendency within a community (Feature 029).

Represents the prevailing direction of collective consciousness — the default drift without active organizing.

Values:
LIBERAL: Seeks inclusion in existing institutions without transforming

them. Organizational vehicle: liberal CSOs, Democratic Party.

FASCIST: Collaboration with hegemonic order for individual escape.

Strategy: shrink the marginalized definition, exclude the most marginal.

REVOLUTIONARY: Oppositional collective identity, independent power.

The contradiction is material, not a misunderstanding.

LIBERAL = 'liberal'
FASCIST = 'fascist'
REVOLUTIONARY = 'revolutionary'
babylon.models.CommunityConsciousness

alias of TernaryConsciousness

class babylon.models.ContradictionType(*values)[source]

Bases: StrEnum

Main axes of structural contradiction (Constitutional Framework).

Moving away from hardcoded models towards a dynamic Maoist contradiction framework. Defines the principal and secondary axes at a given scale.

NATIONAL = 'national'
CLASS = 'class'
GENDER = 'gender'
IMPERIAL = 'imperial'
ECOLOGICAL = 'ecological'
class babylon.models.TernaryConsciousness(**data)[source]

Bases: BaseModel

A point in the 2-simplex representing community consciousness.

Three components (r, l, f) sum to 1.0: - r: Revolutionary consciousness (distance from assimilation). - l: Liberal consciousness (reform within existing order). - f: Fascist consciousness (exclusionary reaction).

Supports two construction paths: 1. Native: TernaryConsciousness(r=0.5, l=0.3, f=0.2) 2. Legacy: ``TernaryConsciousness(collective_identity=0.5,

dominant_tendency=LIBERAL, ideological_contestation=0.4)``

Both produce valid simplex points with backward-compatible properties.

Parameters:
  • r (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Revolutionary component [0, 1].

  • l (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Liberal component [0, 1].

  • f (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Fascist component [0, 1].

  • contestation_stored (float | None) – Preserved legacy contestation value, or None for natively constructed instances (uses Shannon entropy).

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

r: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
l: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
f: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
contestation_stored: float | None
property collective_identity: float

Oppositional consciousness [0, 1]. Equals r component.

Returns:

The revolutionary component, semantically identical to the old CommunityConsciousness.collective_identity.

property dominant_tendency: ConsciousnessTendency

Prevailing ideological direction (argmax of r, l, f).

Ties are broken in favor of liberal (structural advantage of the status quo — you have to actively organize to leave liberalism).

Returns:

ConsciousnessTendency corresponding to the largest component.

property ideological_contestation: float

Active debate between tendencies [0, 1].

If contestation_stored is set (legacy construction), returns that value for backward compatibility. Otherwise computes normalized Shannon entropy of (r, l, f): H(r,l,f) / log(3).

Returns:

Contestation level. 0 = monopoly, 1 = maximum contestation.

property assimilation_ratio: float

f / (l + f).

Measures how much of the non-revolutionary consciousness is fascist. When l + f is near zero (fully revolutionary), returns 0.5 (neutral).

Returns:

Ratio in [0, 1]. 0 = pure liberal, 1 = pure fascist.

Type:

Position along the liberal-fascist base

class babylon.models.SubstrateFloor(**data)[source]

Bases: BaseModel

Per-community-type minimum revolutionary consciousness with provenance.

The substrate floor is consciousness that persists even when all organizations are destroyed — the grandmother teaching not to talk to cops, survival knowledge transmitted through socialization.

Parameters:
  • community_type (CommunityType) – Which community this floor applies to.

  • floor_value (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Minimum r regardless of org landscape [0, 1].

  • confidence (ProvenanceLevel) – Data quality indicator.

  • data_sources (list[str]) – Named data sources used.

  • computation_method (str) – How floor was derived from proxies.

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

community_type: CommunityType
floor_value: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
confidence: ProvenanceLevel
data_sources: list[str]
computation_method: str
class babylon.models.ProvenanceLevel(*values)[source]

Bases: StrEnum

Data quality indicator for substrate floor computation.

Values:

HIGH: Derived from 2+ independent proxy data sources. MEDIUM: Derived from 1 proxy data source. LOW: Estimated from related data, not direct proxy. SYNTHETIC: Stipulated placeholder with no data path.

HIGH = 'high'
MEDIUM = 'medium'
LOW = 'low'
SYNTHETIC = 'synthetic'
class babylon.models.OrgContribution(**data)[source]

Bases: BaseModel

An organization’s weighted contribution to community consciousness.

Used as input to the compute_ternary_consciousness function.

Parameters:
  • tendency (ConsciousnessTendency) – Which vertex this org pulls toward.

  • membership_density (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Members in community / community population [0, 1].

  • cadre_level (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Organizational development level [0, 1].

  • cohesion (Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=~babylon.kernel.math.quantize)]) – Internal organizational cohesion [0, 1].

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tendency: ConsciousnessTendency
membership_density: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
cadre_level: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]
cohesion: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Value in range [0.0, 1.0] representing likelihood', metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]

Types

Constrained value types for the Babylon simulation.

These Annotated type aliases provide runtime validation for numeric values. Using Pydantic v2’s Annotated pattern allows these types to be used directly in any BaseModel field.

Types defined:

Probability: [0.0, 1.0] - for P(S|A), P(S|R), tension Ideology: [-1.0, 1.0] - revolutionary to reactionary spectrum Currency: [0.0, inf) - wealth, wages, rent, GDP Intensity: [0.0, 1.0] - contradiction intensity Coefficient: [0.0, 1.0] - formula parameters (alpha, lambda, k) Ratio: (0.0, inf) - wage ratios, exchange ratios EntityProtocol: Protocol for entities with lifecycle state (Sprint 1.X D2)

Usage:

from babylon.models.types import Probability, Currency

class SurvivalState(BaseModel):

p_acquiescence: Probability # Automatically validated [0, 1] wealth: Currency # Automatically validated [0, inf)

All types serialize to plain floats in JSON for compatibility with the Ledger (SQLite) and NetworkX graph storage.

Epoch 0 Physics Hardening (Gatekeeper Pattern):

All constrained types apply SnapToGrid quantization via AfterValidator. Values are snapped to a 10^-5 grid (0.00001 resolution) to prevent floating-point drift accumulation over long simulations.

babylon.models.types.Probability

[0.0, 1.0]

A probability represents the likelihood of an event occurring. Used for: - P(S|A): Probability of survival through acquiescence - P(S|R): Probability of survival through revolution - tension: Contradiction tension level

Boundary values: - 0.0 = impossible event - 1.0 = certain event

Note: Values are quantized to 10^-5 precision via SnapToGrid.

Type:

Probability

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Value in range [0.0, 1.0] representing likelihood’, metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]

babylon.models.types.Ideology

[-1.0, 1.0]

A class’s ideological position on the revolutionary-reactionary spectrum. Based on consciousness drift formula: dPsi_c/dt = k(1 - Wc/Vc) - lambda*Psi_c

Boundary values: - -1.0 = fully revolutionary (class conscious, anti-capitalist) - +1.0 = fully reactionary (false consciousness, pro-status-quo) - 0.0 = neutral/apolitical

Note: Values are quantized to 10^-5 precision via SnapToGrid.

Type:

Ideology

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Ideological position from revolutionary (-1) to reactionary (+1)’, metadata=[Ge(ge=-1.0), Le(le=1.0)]), AfterValidator(func=quantize)]

babylon.models.types.Currency

[0.0, inf)

Economic value that cannot be negative. Used for: - wealth: Accumulated resources - wages: Payment for labor - rent: Imperial rent (Phi) - GDP: Aggregate output

Note: Debt is not modeled as negative currency but as a separate relationship/obligation between entities.

Note: Values are quantized to 10^-5 precision via SnapToGrid.

Type:

Currency

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Non-negative economic value (wealth, wages, rent, GDP)’, metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]

babylon.models.types.Intensity

[0.0, 1.0]

The intensity of a dialectical contradiction. When intensity reaches 1.0, the contradiction triggers a phase transition (synthesis, rupture, or suppression).

Boundary values: - 0.0 = dormant (contradiction exists but not manifest) - 1.0 = rupture threshold (phase transition imminent)

Note: Values are quantized to 10^-5 precision via SnapToGrid.

Type:

Intensity

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Contradiction intensity from dormant (0) to rupture (1)’, metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]

babylon.models.types.Coefficient

[0.0, 1.0]

A parameter that modifies the strength of an effect in formulas. Used for: - alpha: Extraction efficiency in imperial rent - lambda: Decay rate in consciousness drift - k: Sensitivity coefficient in survival calculus

Boundary values: - 0.0 = no effect - 1.0 = maximum effect

Note: Values are quantized to 10^-5 precision via SnapToGrid.

Type:

Coefficient

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Formula parameter in range [0, 1]’, metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]

babylon.models.types.Ratio

(0.0, inf)

A ratio comparing two quantities. Zero is invalid because ratios typically represent division results.

Used for: - Wc/Vc: Labor aristocracy ratio (wages to value produced) - epsilon: Exchange ratio in unequal exchange

Interpretation: - Ratio = 1.0: Equal exchange / fair wages - Ratio > 1.0: Core receives more than it gives (exploitation) - Ratio < 1.0: Core receives less than it gives

Note: Values are quantized to 10^-5 precision via SnapToGrid.

Type:

Ratio

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Positive ratio comparing two quantities’, metadata=[Gt(gt=0.0)]), AfterValidator(func=quantize)]

babylon.models.types.LaborHours

[0.0, inf)

Labor-time measurement in hours. Used for the fundamental tensor primitive where all economic values are expressed in labor-time, not monetary units.

Used for: - Primitive tensor cells (c, v, s components) - Aggregated labor-time values - SNLT-converted wage data

The distinction from Currency is semantic: Currency represents monetary value, LaborHours represents socially necessary labor time (SNLT).

Note: Values are quantized to 10^-6 precision via SnapToGrid.

Type:

LaborHours

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Non-negative labor-time measurement in hours’, metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]

babylon.models.types.SignedLaborHours

(-inf, +inf)

Labor-time measurement that can be negative. Used for derived tensors where negative values have economic meaning.

Used for: - Imperial rent (Φ): Positive = core (receiving rent), Negative = periphery (donating rent) - Net value flows between territories - Derived economic calculations

Unlike LaborHours, this type permits negative values because: - Negative imperial rent indicates periphery status (donating more value than receiving) - Net flows can be negative (outflow > inflow)

Note: Values are quantized to 10^-6 precision via SnapToGrid.

Type:

SignedLaborHours

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Labor-time measurement allowing negative values’), AfterValidator(func=quantize)]

babylon.models.types.Gini

[0.0, 1.0]

Intra-class inequality coefficient (Mass Line Refactor). Determines what fraction of wealth the marginal worker (bottom 40%) receives.

Used for: - inequality: Intra-class wealth distribution within a demographic block

Boundary values: - 0.0 = Perfect equality (mean = median, everyone gets equal share) - 1.0 = Maximum tyranny (Pareto extreme: bottom majority has nothing)

The Grinding Attrition Formula uses this to calculate marginal wealth:

marginal_wealth = per_capita_wealth × (1 - gini)

At gini=0: marginal_wealth = average (all survive if average suffices) At gini=1: marginal_wealth = 0 (marginal workers always starve)

Note: Values are quantized to 10^-5 precision via SnapToGrid.

Type:

Gini

alias of Annotated[float, FieldInfo(annotation=NoneType, required=True, description=’Gini coefficient measuring intra-class inequality’, metadata=[Ge(ge=0.0), Le(le=1.0)]), AfterValidator(func=quantize)]

class babylon.models.types.EntityProtocol(*args, **kwargs)[source]

Bases: Protocol

Protocol for entities with lifecycle state.

Any object implementing this protocol can be checked for death using is_dead() or similar lifecycle functions. This prevents type errors where floats, dicts, or other non-entity types are accidentally passed to lifecycle functions.

Implementors:
  • SocialClass: Has active field (True = alive, False = dead)

Sprint 1.X D2 Pain Point #3: Loose typing allowed bugs like is_dead(float) instead of is_dead(Entity).

Example

>>> from babylon.models.types import EntityProtocol
>>> from babylon.models import SocialClass
>>>
>>> worker = SocialClass(id="C001", name="Worker", ...)
>>> isinstance(worker, EntityProtocol)  # True
>>> is_dead(worker)  # Works
>>>
>>> is_dead(0.5)  # TypeError: expected EntityProtocol
__init__(*args, **kwargs)
property active: bool

Whether the entity is alive/active.

Returns:

True if the entity is alive, False if dead.

World State

WorldState model for the Babylon simulation.

WorldState is an immutable snapshot of the entire simulation at a specific tick. It encapsulates: - All entities (social classes) as nodes - All territories (strategic sectors) as nodes - All relationships (value flows, tensions) as edges - A tick counter for temporal tracking - An event log for narrative/debugging

The state is designed for functional transformation:

new_state = step(old_state, config)

Sprint 4: Phase 2 game loop state container with NetworkX integration. Sprint 3.5.3: Territory integration for Layer 0.

class babylon.models.world_state.WorldState(**data)[source]

Bases: BaseModel

Immutable snapshot of the simulation at a specific tick.

WorldState follows the Data/Logic separation principle: - State holds WHAT exists (pure data) - Engine determines HOW it transforms (pure logic)

This enables: - Determinism: Same state + same engine = same output - Replayability: Save initial state, replay entire history - Counterfactuals: Modify a parameter, run forward, compare - Testability: Feed state in, assert on state out

Parameters:
tick

Current turn number (0-indexed)

entities

Map of entity ID to SocialClass (the nodes)

territories

Map of territory ID to Territory (Layer 0 nodes)

relationships

List of Relationship edges (the edges)

event_log

Recent events for narrative/debugging (string format)

events

Structured simulation events for analysis (Sprint 3.1)

economy

Global economic state for dynamic balance (Sprint 3.4.4)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tick: int
entities: dict[str, SocialClass]
territories: dict[str, Territory]
relationships: list[Relationship]
event_log: list[str]
events: list[SimulationEvent]
economy: GlobalEconomy
state_finances: dict[str, StateFinance]
contradiction_frames: dict[str, ContradictionFrame]
opposition_states: dict[str, Any]
organizations: dict[str, Annotated[StateApparatus | Business | PoliticalFaction | CivilSocietyOrg, FieldInfo(annotation=NoneType, required=True, discriminator='org_type')]]
key_figures: dict[str, KeyFigure]
institutions: dict[str, Institution]
institution_relations: list[InstitutionOrgRelation]
industries: dict[str, IndustryHyperedge]
sovereigns: dict[str, Sovereign]
factions: dict[str, BalkanizationFaction]
to_graph()[source]

Convert state to a BabylonGraph for formula application.

The rustworkx-backed BabylonGraph (Amendment L) replaces the former NetworkX DiGraph; its nx-compat authoring surface keeps this method’s body and all downstream readers unchanged, and it satisfies GraphProtocol directly so systems no longer wrap per tick.

Nodes are entity/territory IDs with all fields as attributes. A _node_type marker distinguishes between node types: - _node_type=’social_class’ for SocialClass nodes - _node_type=’territory’ for Territory nodes

Edges are relationships with all Relationship fields as attributes.

Graph metadata (G.graph) contains: - economy: GlobalEconomy state (Sprint 3.4.4)

Return type:

BabylonGraph

Returns:

BabylonGraph with nodes and edges from this state.

Raises:

ValueError – If two relationships share a (source, target) pair with differing edge_types — BabylonGraph stores one edge per pair, so the collision would silently collapse last-writer-wins (Design B fail-loud).

Example:

G = state.to_graph()
for node_id, data in G.nodes(data=True):
    if data["_node_type"] == "social_class":
        data["wealth"] += 10  # Modify entity
new_state = WorldState.from_graph(G, tick=state.tick + 1)
classmethod from_graph(G, tick, event_log=None, events=None)[source]

Reconstruct WorldState from a BabylonGraph.

Parameters:
  • G (BabylonGraph) – Graph with node/edge data (BabylonGraph — the sole substrate since Amendment L closed the adapter seam)

  • tick (int) – The tick number for the new state

  • event_log (list[str] | None) – Optional event log to preserve (backward compatibility)

  • events (list[SimulationEvent] | None) – Optional structured events to include (Sprint 3.1)

Return type:

WorldState

Returns:

New WorldState with entities, territories, and relationships from graph.

Example

G = state.to_graph() # … modify graph … new_state = WorldState.from_graph(G, tick=state.tick + 1)

add_entity(entity)[source]

Return new state with entity added.

Parameters:

entity (SocialClass) – SocialClass to add

Return type:

WorldState

Returns:

New WorldState with the entity included.

Example

new_state = state.add_entity(worker)

add_territory(territory)[source]

Return new state with territory added.

Parameters:

territory (Territory) – Territory to add (Layer 0 node)

Return type:

WorldState

Returns:

New WorldState with the territory included.

Example

new_state = state.add_territory(university_district)

add_relationship(relationship)[source]

Return new state with relationship added.

Parameters:

relationship (Relationship) – Relationship edge to add

Return type:

WorldState

Returns:

New WorldState with the relationship included.

Example

new_state = state.add_relationship(exploitation_edge)

add_event(event)[source]

Return new state with event appended to log.

Parameters:

event (str) – Event description string

Return type:

WorldState

Returns:

New WorldState with event in log.

Example

new_state = state.add_event(“Worker crossed poverty threshold”)

property total_biocapacity: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]

Global sum of territory biocapacity.

property total_consumption: Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Non-negative economic value (wealth, wages, rent, GDP)', metadata=[Ge(ge=0.0)]), AfterValidator(func=quantize)]

Global sum of consumption needs.

property overshoot_ratio: float

Global ecological overshoot ratio.

Configuration

Run-scoped configuration for the Babylon engine.

SimulationConfig carries per-run settings that are not game-balance coefficients. Historically it also declared every formula coefficient, but those fields were dead: the engine reads all tunable coefficients from GameDefines (via services.defines.*), the canonical single source of truth. The ~36 shadow coefficient fields were removed in the src/ simplification sweep (2026-07) — they had zero logic readers, and their values had drifted out of sync with the live GameDefines values (e.g. comprador_cut read 0.15 here vs the live 0.90 in GameDefines.economy), making them an active source of confusion.

Only the deterministic RNG seed remains: the web bridge threads it from the GameSession and serializes it into the persisted config_json blob, so it is a genuine run-scoped setting rather than a coefficient shadow.

See also

GameDefines: canonical coefficient source

and the moddable single source of truth (src/babylon/data/defines.yaml).

class babylon.models.config.SimulationConfig(**data)[source]

Bases: BaseModel

Immutable per-run settings for the simulation engine.

Game-balance coefficients live in GameDefines (read via services.defines); this model only carries run-scoped settings that are not part of the moddable coefficient surface. The config is frozen to preserve determinism during a run.

Parameters:

rng_seed (int)

rng_seed

Per-run RNG seed for byte-identical action replays (Constitution III.7). Threaded from the GameSession by the web bridge and serialized into the persisted run configuration.

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

rng_seed: int