# Tribal Village Temple Role System (Notes)

This doc summarizes the role-mixing system in `tribal-village` so we can port a homologous evolution system into
`richard-evolution`. We are not bringing the temple building itself; the focus is on the role catalog, recombination,
and mutation mechanics. It is descriptive, not a proposal.

## Where it lives (tribal-village)

- `src/scripted/ai_defaults.nim`: role assignment, role pool, temple hybrid flow.
- `src/scripted/roles.nim`: role/behavior catalog, tiers, materialization.
- `src/scripted/evolution.nim`: sampling, recombination, mutation, scoring.
- `src/step.nim`: temple spawn that triggers hybrid requests.
- `src/types.nim`: `TempleHybridRequest` definition.

## Core model

- **BehaviorDef**: wraps an `OptionDef` plus fitness, games, uses.
- **RoleDef**: list of tiers (`RoleTier`), origin, kind (Gatherer/Builder/Fighter/Scripted), fitness and win tracking,
  optional name lock.
- **RoleTier**: ordered behavior IDs with a selection mode:
  - fixed: use given order
  - shuffle: randomize per materialization
  - weighted: weighted shuffle using tier weights
- **RoleCatalog**: holds behavior and role registries and can serialize history to `data/role_history.json`.

## Option execution (behavior list)

Roles are materialized into `OptionDef` sequences (`materializeRoleOptions`) and executed by `runOptions` (in
`options.nim`): the active option runs until it terminates or returns 0, otherwise higher-priority options can pre-empt
if they are marked interruptible.

## Role pool + assignment

- Core roles are built from Gatherer/Builder/Fighter option lists.
- A role pool is built from all non-core roles; if none exist, core roles are used as a fallback pool.
- Scripted agents can either explore (generate a new role) or sample a role from the pool weighted by role fitness.
- `ScriptedRoleExplorationChance` = 0.08, `ScriptedRoleMutationChance` = 0.25, `ScriptedGeneratedRoleCount` = 16.

## Evolution and scoring

- `sampleRole` builds N tiers (2-4) with 1-3 behaviors per tier, chosen with weights based on behavior fitness.
- `recombineRoles` splices tier ranges from two parents at random cut points.
- `mutateRole` can replace behavior IDs and flip tier selection modes.
- `applyScriptedScoring` scores roles and behaviors using territory share at `ScriptedScoreStep` (5000), updating EMA
  fitness and persisting history.
- `lockRoleNameIfFit` freezes names once fitness crosses 0.7.

## Temple hybrid flow

1. **Spawn trigger** (`src/step.nim`): when two adjacent agents of the same team stand next to a Temple and an altar
   heart is available, a child agent is spawned. A `TempleHybridRequest(parentA, parentB, childId, teamId, pos)` is
   queued.
2. **Processing** (`processTempleHybridRequests` in `ai_defaults.nim`):
   - Lookup each parent's current role.
   - `recombineRoles` to build a hybrid role.
   - Optional mutation and an extra behavior injection (35% chance) into the first tier (`injectBehavior`).
   - Mark role origin as `"temple"` and register it in the catalog.
   - Add to role pool and mark `pendingHybridRoles[childId]`.
   - Reset the child agent init flag so the hybrid is applied next tick.
3. **Assignment** (`assignScriptedRole`): if a pending hybrid is set, the child is assigned the new role immediately
   before any other selection.

## Metta adaptation (no temple building)

- We want the same role catalog, tier recombination, and mutation mechanics.
- The trigger is **not** a temple spawn. It can be end-of-episode, a fixed cadence, or an external coordinator signal.
- Hybrid roles are still generated by recombining two parent roles, then optionally mutating/injecting a behavior.

## What this implies for our port

- We need a **role catalog** that can compose option lists from behaviors and persist fitness history.
- The **temple trigger** is an environment event (spawn/interaction) that queues a hybrid request, not an agent
  decision.
- Hybridization is **tier-based recombination** with optional mutation and behavior injection, then assignment to the
  newborn agent.
- The system is light-weight: it relies on option lists rather than training.

## Current richard-evolution implementation

- Core evolution logic: `packages/cogames-agents/src/cogames_agents/policy/evolution/cogsguard/evolution.py`.
- Coordinator and role selection:
  `packages/cogames-agents/src/cogames_agents/policy/evolution/cogsguard/evolutionary_coordinator.py`.
- Trigger today is **coordinator-driven** (games per generation), not an environment event.
- `CogsguardPolicy` can opt into evolutionary role selection via URI flags (`evolution=1`, `evolutionary=1`, or
  `evolve=1`).
- Behavior hooks are wired up for integration (see
  `packages/cogames-agents/src/cogames_agents/policy/scripted_agent/cogsguard/behavior_hooks.py`): the coordinator can
  call real role behaviors when hooks are provided, but live execution still uses vibe-based roles.

## Gaps vs an across-episode evolution loop

- **No episode trigger wired yet.** `record_agent_performance` and `end_game` exist but are not called from the policy,
  so fitness stays at defaults and selection is effectively uniform.
- **Evolved roles don’t drive behavior.** Roles are mapped back to base vibes, so recombination/mutation does not change
  the actual action ordering or per-step decisions.
- **No persistence.** Role/behavior history isn’t saved or loaded (no `role_history.json` analog), so evolution resets
  per run.

## Suggested wiring (future work)

1. **Episode completion → scoring**
   - Pick a stable signal (team score, win/loss, hearts/influence delta, territory control).
   - Call `record_agent_performance(agent_id, score, won)` per agent at episode end.
   - Call `end_game(won)` to advance generations after `games_per_generation`.

2. **Role execution path**
   - Decide whether evolved roles should execute **behavior lists** (preferred) or keep mapping to base vibes.
   - If using lists, materialize behaviors and run them via `run_options` (interruptible, priority tiers).
   - Map behavior names to real role actions via `behavior_hooks` (already available).

3. **Persistence**
   - Serialize `RoleCatalog` fitness + usage into a JSON file under `data/` (or run output dir).
   - Load history at coordinator init (matching tribal-village’s `role_history.json` pattern).

4. **Coordinator integration**
   - Keep `SmartRoleCoordinator` as fallback when evolution is disabled.
   - For `evolution=1`, use the evolutionary coordinator for **gear** decisions and optionally replace smart-role
     reassignment logic in `_maybe_switch_smart_role`.

5. **Testing additions**
   - Add unit tests for persistence (save/load round-trip, fitness continuity).
   - Add integration tests for scoring triggers (episode end increments generation).
   - Add behavior-execution tests to ensure evolved tiers change option order.

## Open questions to resolve

- What is the authoritative “score” for a role? (team win/loss, territory share, resource throughput, alignment control)
- Should evolution be per-team or global across teams? (fitness updates per team vs pooled)
- What cadence should evolve roles? (fixed games, fixed steps, external evaluation)
- How much variance is acceptable before locking names / freezing roles?
