This page explains the internal workings of Ometeotl/ometeotl_core at three depth levels.
For API-level details, use Class Reference.
04/25/26 - major architectural overhaul: Local tests reveal the current architecture is too abstract for any practical implementation. It has been decided to :
- to keep the current code in a core module
ometeotl_core, which is intended to remain abstract; - to add a primary layer of specialization
ometeotl_foundations, including :- spatial: primary layer of spatial implementation of
ometeotl_core; - networks: primary layer of graph theory implementation of
ometeotl_core - …
- spatial: primary layer of spatial implementation of
- to add, lastly, an adapter layer
ometeotl_adapters, which implements each specialization layer with a reputable library.
Beginner View
Ometeotl/ometeotl_core is a modeling library where everything starts from a generic object, then becomes more specific.
- ModelObject is the universal base container.
- GenericObject adds practical metadata such as labels, tags, and profiles.
- Actor, Resource, Space, and Action represent core domain entities.
- World is the top-level container that organizes spaces, objects, and their relations.
The library tracks where objects exist with:
Each actor can have a subjective, possibly imperfect view of the world:
- Sensor builds a Perception
- CoverageRule controls what is visible
- NoiseRule controls how observed data is distorted
Actors may also form explicit composite hierarchies and abstraction layers:
- Actor supports explicit
componentrelations forcompositeactors and helper utilities for hierarchy traversal and cycle checks - Space can be marked
is_abstractto represent conceptual or analytical spaces alongside canonical spaces - Perception can carry perceived component links, keeping composition knowledge in the epistemic layer when needed
Candidate actions can then be projected from that perceived state into explicit future-facing strategy artifacts:
- DefaultProjectionTool derives projection assumptions and successor perceived states
- ProjectedPerceptionState stores the projected successor perception for one action
- StrategyNode anchors one action and its input perceived state to an ordered set of StrategyOutcomeBranch links; each branch carries its own projected successor perceived state
- Strategy groups nodes into a linear or branching perception-driven tree
Teleology, utility/ranking, and multi-actor game structures are now implemented as model and game extensions:
- Goal and GoalDecompositionTree represent final or intermediate objectives and hierarchical decomposition.
- GoalAdmissibilityChecker and DefaultGoalFeasibilityTool provide model-level feasibility and admissibility checks.
- UtilityFunction defines the abstract utility contract.
- WeightedSumUtility, LexicographicUtility, and StrategyRanker provide game-layer utility derivation and strategy ranking over projected terminal states.
- PlayerProfile and GameState bind actors to their admissible strategies and capture the multi-actor game snapshot.
- NormalFormGame builds the full payoff matrix from a GameState by enumerating all strategy profile combinations through a PayoffFunction.
- BestResponseCalculator finds the utility-maximising strategy for a focal actor against fixed opponent strategies.
Model objects can also be generated programmatically from declarative inputs:
- GenerationContext is the declarative input carrying identity, attributes, nested child contexts, placements, and constraints.
- ContextualGenerationPipeline orchestrates rule application, builder dispatch, optional registration, and optional validation.
- GenerationRule / GenerationRuleSet / RuleRegistry provide pluggable constraint propagation (temporal, spatial, admissibility).
- LLMGenerationAdapter enables optional LLM-assisted context refinement before building.
to_llm_view()on any model object exports a language-model-oriented payload with explicit reality/perception separation (LLM view export).
For server-authoritative setups, mutations can be routed through:
Intermediate View
The implemented pipeline follows this flow:
- Build domain entities from ModelObject-derived classes such as Actor, Resource, Space, and Action.
- Register objects in WorldModelRegistry through World.
- Place object-space memberships in SpaceObjectGraph.
- Add space-to-space edges in SpaceRelationGraph.
- Serialize deterministically with
to_dict()methods (canonical sorting for stable diffs). - Rebuild canonical objects with
from_dict()methods. - Generate actor-relative snapshots via Sensor into Perception.
- Derive first-order projection assumptions and projected successor perceived states from candidate actions, one Perception, and available resources through DefaultProjectionTool.
- Build a perception-driven Strategy with build_linear_strategy(…) or build_branching_strategy(…).
- Validate payloads/objects with the staged validation pipeline in
ometeotl_core.validation(syntactic, structural, temporal, spatial, admissibility, epistemic, completeness), using policy profiles (observe_only,enforce_structure,enforce_domain) when needed. - Export a world to canonical JSON or YAML via
ometeotl_core.io(world_to_json, world_to_yaml, write_world_json, write_world_yaml). - Re-import a world from JSON or YAML with validated reconstruction via world_from_json / world_from_yaml, which runs syntactic then structural validation before calling
World.from_dict. - Export any entity as a language-model-oriented payload via
to_llm_view()(LLM view export), which separates ontological reality from epistemic/perception-aware views. - Optionally enforce command gating with AuthorityCommandHandler.
- Represent actor objectives with Goal and optionally decompose them with GoalDecompositionTree.
- Link Strategy to a goal and evaluate admissibility with GoalAdmissibilityChecker.
- Evaluate strategy outcomes with a UtilityFunction implementation and rank with StrategyRanker.
- Build a multi-actor game by wrapping players in PlayerProfile objects and grouping them into a GameState, then calling NormalFormGame.from_game_state(…) with an IndependentPayoffFunction to compute the full payoff matrix.
- Find best responses with BestResponseCalculator.compute(…) given fixed opponent strategies.
- Generate model objects programmatically from declarative GenerationContext inputs using ContextualGenerationPipeline, with optional constraint propagation via the rule engine and optional LLM-assisted context refinement via LLMGenerationAdapter.
Operationally, World composes three independent graphs/registries:
- membership topology: SpaceObjectGraph
- spatial topology: SpaceRelationGraph
- object identity and lookup: WorldModelRegistry
This separation prevents layer mixing and aligns with the architecture constraints in specs_EN.md.
Test Layout
The test suite follows the same layer separation as the source tree:
tests/ometeotl_core/model/: tests forometeotl_core.model.*tests/ometeotl_core/generic/: tests forometeotl_core.generic.*tests/ometeotl_core/validation/: tests forometeotl_core.validation.*tests/ometeotl_core/game/: tests forometeotl_core.game.*tests/ometeotl_core/io/: tests forometeotl_core.io.*tests/ometeotl_core/generation/: tests forometeotl_core.generation.*
Within each layer folder, tests are split by module using one file per module (test_<module>.py).
Run the complete suite from the repository root in one command:
pytest
Expert View
At expert level, the core implementation can be read as a set of deterministic state-transition boundaries.
1. Canonical object schema boundary
Every serializable entity normalizes to canonical JSON dictionaries:
- base schema from ModelObject
- extended schema in Action, World, and Perception
Deterministic ordering is enforced by canonical sort helpers and sorted list serialization, making snapshots stable for audit/diff workflows.
2. Ontology boundary vs epistemic boundary
The ontology layer is World, SpaceObjectGraph, SpaceRelationGraph, and WorldModelRegistry.
The epistemic layer is Perception, PerceivedSpace, PerceivedMembership, and PerceivedRelation, created by Sensor through composable CoverageRule and NoiseRule.
Perceived actor composition is represented explicitly through PerceivedComponentLink, which lets perceived hierarchies diverge from ontological hierarchies without mixing layers.
This realizes reality/perception dissociation from the spec: decisions can be based on perceived states, not only ontological states.
3. Authority boundary
When authority mode is enabled in World, direct mutations require a token.
AuthorityCommandHandler provides a single command path that enforces:
- command allowlisting
- command id deduplication
- actor existence checks
- strictly increasing sequence checks per actor
- bounded in-memory tracking for processed ids and sequence history
- immutable audit traces with AuditEntry
- staged validation with configurable hardening profiles (
observe_only,enforce_structure,enforce_domain) - structured validation summaries attached to command results and audit entries
4. LLM export boundary
to_llm_view() is defined on ModelObject and dispatches to LLMViewBuilder by object type.
The export path (F-5) keeps ownership clean:
modelowns canonical state (to_dictand domain classes)ioowns formatting and projection for external consumers
Output always exposes explicit epistemic distinctions: reality, perception, belief, hypothesis, projection. Collections and epistemic groups are produced deterministically (sorted keys).
5. Generation boundary
The generation layer (F-16 to F-22) converts declarative GenerationContext inputs into model objects through a deterministic pipeline:
GenerationContext
→ GenerationRuleSet.apply() # constraint propagation, normalization
→ build_from_context() # kind dispatch to builder functions
→ registration / validation # optional; driven by context flags
→ GenerationResult
Key design properties:
- Rule application is purely functional: each rule receives a context and returns a new one via
copy_with. - RuleRegistry enables pluggable policy selection at call-site without modifying the pipeline.
- LLMGenerationAdapter is explicitly chained by callers — the pipeline never calls it automatically.
- Constraint propagation rules use
setdefaultsemantics, making the pipeline non-destructive: existing metadata survives rule application.
4. Extensibility seam
Primary extension seams are intentionally abstract and composable:
- CoverageRule and NoiseRule for sensing behavior
- custom object reconstruction factories through registry helpers and authority handlers
- custom command handlers injected into AuthorityCommandHandler
5. Runtime wiring
RuntimeContext plus build_runtime(...) provide explicit mode selection:
- local mode: direct world mutation APIs
- server-authoritative mode: command-gated mutation via AuthorityCommandHandler
When server-authoritative mode is enabled, runtime also wires validation policy options (validation_soft_gate, validation_policy_profile, validation_stage_mode_overrides, validation_block_on_error, validation_completeness_level) through to the authority boundary.
This keeps local testing ergonomics while preserving an enforceable server boundary for multi-client systems.
6. First-order projection seam
DefaultProjectionTool is intentionally separate from the strategy model layer.
It consumes Action, Perception, and Resource inputs and emits ProjectionAssumption collections grouped as ActionProjection or ProjectionBatch, together with a ProjectedPerceptionState representing the successor perceived state for that action.
This keeps first-order projection focused on assumption building plus successor-state derivation, while leaving later strategy-node construction and branching as a separate concern.
7. Strategy chaining seam
The strategy layer is implemented in Strategy, StrategyNode, StrategyOutcomeBranch, and StrategyBuildStep.
The important rule is that a strategy node is anchored to:
- one action id
- one source perception id (the perceived state the action is applied from)
- an ordered list of StrategyOutcomeBranch links, each carrying its own projected successor perceived state
validate_tree() enforces two invariants per branch:
- if a branch’s
projected_stateis present, itsgenerating_action_idmust match the parent node’saction_id - if a branch links to a child node and carries a
projected_state, the child node’ssource_perception_idmust equal the branch’s projected perception id
This makes strategy hops explicitly perception-driven and allows one action to produce several distinct outcomes across sibling branches.
8. Builder seam
Two minimal builders exist today in src/ometeotl_core/model/strategies.py:
build_linear_strategy(...)for ordered action sequencesbuild_branching_strategy(...)for recursive action trees built from StrategyBuildStep
Both builders project each action from the currently active perceived state and attach the resulting successor perceived state to the outgoing branches of each node.
build_branching_strategy(...) allows one action to branch into several sibling child steps: all sibling branches from a node share the same parent action’s projected state, while each child subtree is projected from that shared successor perception onward.
9. Teleology and game utility seam
The teleology seam is now explicit in the model layer through Goal and GoalDecompositionTree, while goal evaluation remains domain-neutral via GoalFeasibilityTool and GoalAdmissibilityChecker.
The game utility seam is explicit in UtilityFunction plus concrete game-layer combinators WeightedSumUtility and LexicographicUtility.
StrategyRanker evaluates terminal projected states and aggregates branch probabilities in a deterministic way, including directed acyclic strategy graphs with merged terminal paths.
The multi-actor game seam is implemented as three composable layers:
Game state — PlayerProfile binds an actor to its admissible strategies and utility function. GameState groups players into a snapshot with a
world_idreference, realizing G-1 (actors → players) and G-3 (world state → game state).Normal form — NormalFormGame.from_game_state(…) enumerates the Cartesian product of all players’ strategy lists and evaluates each profile through a PayoffFunction. The V1 concrete implementation, IndependentPayoffFunction, delegates per-player evaluation to StrategyRanker — no logic is duplicated. The abstraction keeps the door open for joint-projection payoff functions without breaking callers.
Best response — BestResponseCalculator.compute(…) operates on a prebuilt NormalFormGame, filters payoff vectors to rows where opponent strategies match, and returns the BestResponseResult with the dominant strategy and a ranked list of all options. Tie-breaking is deterministic (descending utility, then ascending strategy id), consistent with the
rank_keyconvention in RankedStrategy.
