Máquina de Estados Finitos: Implementación Formal

Abstract: El Árbol de la Vida se modela como una máquina de estados finitos determinista (FSM) donde los nodos representan las 10 Sefirot, las transiciones los 22 Senderos, y el estado compartido contiene toda la información del proceso de manifestación. Este documento especifica formalmente la estructura, transiciones, condiciones de routing y garantías del sistema.

1. Definición Formal

1.1 Especificación Matemática

La máquina de estados del Árbol de la Vida se define formalmente como una quíntupla:

M = (Q, Σ, δ, q₀, F)

Donde:

  • Q: Conjunto finito de estados = {Kéter, Jojmá, Biná, Jésed, Guevurá, Tiféret, Nétsaj, Hod, Yesod, Maljut}
  • Σ: Alfabeto de entrada = TreeOfLifeState (estado compartido)
  • δ: Función de transición: Q × Σ → Q
  • q₀: Estado inicial = Kéter
  • F: Estado final = {Maljut}

1.2 Estructura del Estado Compartido

class TreeOfLifeState(TypedDict):
    # Mundo de Atzilut (Emanación)
    intention_raw: str                    # Input del usuario sin procesar
    intention_clean: str                  # Intención destilada (Kéter)
    possibilities: List[str]              # Opciones generadas (Jojmá)
    structure: Dict[str, Any]             # Organización conceptual (Biná)
    
    # Mundo de Beriah (Creación)
    expansions: List[str]                 # Ampliaciones propuestas (Jésed)
    constraints: List[str]                # Límites establecidos (Guevurá)
    balanced_decision: str                # Decisión equilibrada (Tiféret)
    expansion_score: float                # Métrica de expansión [0-1]
    constraint_score: float               # Métrica de contracción [0-1]
    
    # Mundo de Yetzirah (Formación)
    emotional_charge: str                 # Carga motivacional (Nétsaj)
    detailed_plan: Dict[str, List[str]]   # Plan estructurado (Hod)
    integrated_vision: str                # Visión completa (Yesod)
    
    # Mundo de Assiah (Acción)
    concrete_action: str                  # Acción específica (Maljut)
    
    # Metadatos
    current_sephira: str                  # Estado actual
    path_taken: List[str]                 # Historial de transiciones
    iteration_count: int                  # Contador de loops
    max_iterations: int = 20              # Límite de rebalanceo

2. Diagrama de Estados

2.1 Representación Gráfica

┌────────────────────────────────────────────────────────────┐
│                                                            │
│    [START] → KÉTER                                         │
│                ║                                           │
│         ┌──────╬──────┐                                    │
│         ║             ║                                    │
│      JOJMÁ ←─────→ BINÁ                                    │
│         ║             ║                                    │
│         └──────╬──────┘                                    │
│                ║                                           │
│           ┌────▼────┐                                      │
│           │TIFÉRET  │◄────┐ (Orquestador)                 │
│           │  (HUB)  │     │                                │
│           └────┬────┘     │                                │
│                │          │                                │
│         ┌──────┼──────┐   │                                │
│         ║      │      ║   │                                │
│      JÉSED    ║    GUEVURÁ                                 │
│         ║      │      ║   │                                │
│         └──────┼──────┘   │                                │
│                │          │ (loop rebalanceo)              │
│                ▼          │                                │
│         ┌──────────┐      │                                │
│         │ balanced? ├─────┘                                │
│         └────┬─────┘                                       │
│              │ YES                                         │
│         ┌────┼────┐                                        │
│         ║         ║                                        │
│      NÉTSAJ ←───→ HOD                                      │
│         ║         ║                                        │
│         └────╬────┘                                        │
│              ║                                             │
│           YESOD                                            │
│              ║                                             │
│           MALJUT → [END]                                   │
│                                                            │
└────────────────────────────────────────────────────────────┘

Leyenda:
  ║  = Transición fija (siempre ocurre)
  ←─→ = Interacción/sincronización
  ─┐  = Decisión condicional
  ▼  = Flujo descendente

2.2 Estados del Sistema

Estado Tipo Descripción Salidas Posibles
Kéter Inicial Punto de entrada, captura intención → Jojmá, Biná
Jojmá Generador Genera posibilidades infinitas → Biná
Biná Estructurador Organiza conceptualmente → Tiféret
Tiféret Orquestador Evalúa balance y decide ruta → Jésed, Guevurá, Nétsaj, Hod, Yesod
Jésed Expansor Amplifica posibilidades → Tiféret
Guevurá Limitador Establece restricciones → Tiféret
Nétsaj Cargador Añade emoción → Yesod
Hod Planificador Detalla pasos → Yesod
Yesod Integrador Sintetiza visión completa → Maljut
Maljut Final Genera acción concreta → END

3. Tabla de Transiciones

3.1 Transiciones Fijas (Deterministas)

Estas transiciones ocurren siempre, sin condición:

Origen Destino Sendero Inteligencia Transformación
START Kéter - - Recepción de input
Kéter Jojmá 0 Ígnea Chispa → Posibilidades
Kéter Biná 1 Transparente Voluntad → Forma
Jojmá Biná 3 Luminosa Ideas → Estructura
Biná Tiféret 6 Que Dispone Estructura → Evaluación
Jésed Tiféret 10 Recompensadora Expansión → Re-evaluación
Guevurá Tiféret 11 Fiel Límites → Re-evaluación
Nétsaj Yesod 17 Natural Emoción → Integración
Hod Yesod 19 Colectora Plan → Integración
Yesod Maljut 21 Administrativa Visión → Acción
Maljut END - - Output final

3.2 Transiciones Condicionales (desde Tiféret)

Tiféret es el único nodo con múltiples salidas condicionales:

Condición Destino Sendero Inteligencia Razón
expansion_score < 0.4 Jésed 9 Voluntad Necesita más posibilidades
constraint_score < 0.4 Guevurá 11 Fiel Necesita más límites
|exp - con| > 0.3 Loop - - Desequilibrio significativo
balanced AND no_emotion Nétsaj 13 Imaginativa Falta carga emocional
balanced AND no_plan Hod 15 Renovadora Falta plan detallado
balanced AND ready Yesod 14 De Prueba Listo para integrar

4. Lógica del Orquestador (Tiféret)

4.1 Función de Routing Central

def route_from_tiferet(state: TreeOfLifeState) -> str:
    """
    Tiféret evalúa el estado y decide la siguiente transición.
    Esta es la lógica central de toda la máquina de estados.
    
    Returns:
        str: Nombre de la siguiente sefirá de destino
    """
    
    # Protección contra loops infinitos
    if state["iteration_count"] > state["max_iterations"]:
        logger.warning("Max iterations reached, forcing descent")
        return "yesod"
    
    # Calcular métricas de balance
    expansion_score = calculate_expansion_score(state)
    constraint_score = calculate_constraint_score(state)
    balance_delta = abs(expansion_score - constraint_score)
    
    # Prioridad 1: Verificar si necesita más expansión
    if expansion_score < EXPANSION_THRESHOLD:
        state["iteration_count"] += 1
        logger.info(f"Routing to Jesed: low expansion ({expansion_score:.2f})")
        return "jesed"
    
    # Prioridad 2: Verificar si necesita más límites
    if constraint_score < CONSTRAINT_THRESHOLD:
        state["iteration_count"] += 1
        logger.info(f"Routing to Gevura: low constraints ({constraint_score:.2f})")
        return "gevura"
    
    # Prioridad 3: Verificar balance entre fuerzas
    if balance_delta > BALANCE_DELTA_THRESHOLD:
        state["iteration_count"] += 1
        logger.info(f"Rebalancing: delta={balance_delta:.2f}")
        if expansion_score > constraint_score:
            return "gevura"  # Mucha expansión → añadir límites
        else:
            return "jesed"   # Muchos límites → añadir posibilidades
    
    # Balance alcanzado, verificar completitud
    has_emotion = bool(state.get("emotional_charge"))
    has_plan = bool(state.get("detailed_plan"))
    
    # Prioridad 4: Si falta carga emocional
    if not has_emotion:
        logger.info("Routing to Netsaj: needs emotional charge")
        return "netsaj"
    
    # Prioridad 5: Si falta plan detallado
    if not has_plan:
        logger.info("Routing to Hod: needs detailed plan")
        return "hod"
    
    # Todo completo, listo para integrar
    logger.info("Routing to Yesod: all requirements met")
    return "yesod"


def calculate_expansion_score(state: TreeOfLifeState) -> float:
    """
    Calcula qué tan expansiva es la propuesta actual.
    
    Considera:
    - Número de posibilidades generadas
    - Número de expansiones propuestas
    - Amplitud del scope definido
    
    Returns:
        float: Score normalizado [0, 1]
    """
    score = 0.0
    
    # Factor 1: Posibilidades (Jojmá)
    num_possibilities = len(state.get("possibilities", []))
    score += min(num_possibilities / 10.0, 0.4)  # Max 0.4
    
    # Factor 2: Expansiones (Jésed)
    num_expansions = len(state.get("expansions", []))
    score += min(num_expansions / 5.0, 0.3)  # Max 0.3
    
    # Factor 3: Amplitud conceptual
    structure = state.get("structure", {})
    if structure:
        # Analizar número de dimensiones exploradas
        dimensions = len(structure.keys())
        score += min(dimensions / 10.0, 0.3)  # Max 0.3
    
    return min(score, 1.0)


def calculate_constraint_score(state: TreeOfLifeState) -> float:
    """
    Calcula qué tan acotada/limitada está la propuesta.
    
    Considera:
    - Número de constraints establecidos
    - Especificidad de la estructura
    - Límites temporales/financieros/de scope
    
    Returns:
        float: Score normalizado [0, 1]
    """
    score = 0.0
    
    # Factor 1: Constraints explícitos (Guevurá)
    num_constraints = len(state.get("constraints", []))
    score += min(num_constraints / 5.0, 0.4)  # Max 0.4
    
    # Factor 2: Especificidad de estructura
    structure = state.get("structure", {})
    if structure:
        # Buscar indicadores de límites
        limit_keywords = ["máximo", "solo", "únicamente", "límite", "presupuesto"]
        text = str(structure).lower()
        limit_count = sum(1 for kw in limit_keywords if kw in text)
        score += min(limit_count / 3.0, 0.3)  # Max 0.3
    
    # Factor 3: Decisión balanceada (si existe)
    if state.get("balanced_decision"):
        # La existencia de decisión indica trabajo de filtrado
        score += 0.3
    
    return min(score, 1.0)


# Constantes de umbral
EXPANSION_THRESHOLD = 0.4
CONSTRAINT_THRESHOLD = 0.4
BALANCE_DELTA_THRESHOLD = 0.3

4.2 Ejemplo de Ejecución de Routing

Estado de Entrada:

{
  "possibilities": ["coaching", "cursos", "retiros", "app"],
  "structure": {"modelo": "híbrido", "audiencia": "amplia"},
  "expansions": ["comunidad", "podcast", "libros"],
  "constraints": [],
  "iteration_count": 1
}

Cálculo de Scores:

expansion_score = 0.16 + 0.18 + 0.06 = 0.40
constraint_score = 0.0 + 0.0 + 0.0 = 0.0
balance_delta = |0.40 - 0.0| = 0.40

Decisión:

constraint_score (0.0) < CONSTRAINT_THRESHOLD (0.4)
→ Routing to "gevura" (necesita límites)

5. Garantías del Sistema

5.1 Propiedades Formales

Terminación

Teorema: Todo flujo eventualmente llega a Maljut.

Prueba: El contador iteration_count garantiza que después de max_iterations loops, se fuerza el descenso a Yesod incluso sin balance perfecto.

Determinismo

Teorema: Dado el mismo estado, la transición es siempre la misma.

Prueba: La función route_from_tiferet es puramente determinista: no usa aleatoriedad, timestamps, ni estado externo.

Trazabilidad

Propiedad: El camino completo es registrado.

Implementación: El array path_taken almacena cada transición con timestamp y razón.

Idempotencia

Propiedad: Mismo input → mismo output.

Implicación: El sistema es reproducible y testeable. Útil para debugging y validación.

Monotonía

Propiedad: El flujo general es descendente.

Observación: Aunque hay loops horizontales (Tiféret ↔ Jésed/Guevurá), no hay ascensos (Maljut no puede volver a Kéter).

Completitud

Propiedad: Todos los campos requeridos se llenan.

Verificación: Antes de permitir transición a Maljut, se verifica que todos los campos críticos existan.

5.2 Invariantes del Sistema

Invariante Descripción Verificación
I1: Estado inicial current_sephira == "keter" al inicio Verificado en inicialización
I2: Estado final Solo Maljut puede producir output Guard en cada nodo
I3: Intención preservada intention_clean no se modifica después de Kéter Campo read-only post-Kéter
I4: Path acumulativo path_taken solo crece, nunca decrece Append-only list
I5: Balance eventual Después de rebalanceo, |exp - con| ≤ threshold Post-condición de loop
I6: Campos progresivos Cada mundo añade campos, no los elimina Verificación por nivel

6. Implementación en LangGraph

6.1 Código de Grafo Completo

from langgraph.graph import StateGraph, END
from typing import TypedDict, List, Dict, Any


class TreeOfLifeState(TypedDict):
    """Estado compartido del grafo"""
    # [Ver definición completa en sección 1.2]
    pass


def keter_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Kéter: Captura intención pura"""
    state["intention_clean"] = extract_intention(state["intention_raw"])
    state["current_sephira"] = "keter"
    state["path_taken"].append("START → keter")
    return state


def jojma_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Jojmá: Genera posibilidades"""
    state["possibilities"] = generate_possibilities(state["intention_clean"])
    state["current_sephira"] = "jojma"
    state["path_taken"].append("keter → jojma (Ígnea)")
    return state


def bina_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Biná: Estructura conceptualmente"""
    state["structure"] = create_structure(
        state["intention_clean"],
        state["possibilities"]
    )
    state["current_sephira"] = "bina"
    state["path_taken"].append("jojma → bina (Luminosa)")
    return state


def tiferet_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Tiféret: Evalúa y decide (NO hace routing aquí)"""
    state["expansion_score"] = calculate_expansion_score(state)
    state["constraint_score"] = calculate_constraint_score(state)
    state["current_sephira"] = "tiferet"
    # El routing se hace en conditional_edges, no aquí
    return state


def jesed_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Jésed: Expande posibilidades"""
    state["expansions"] = expand_concept(state["structure"])
    state["current_sephira"] = "jesed"
    state["path_taken"].append("tiferet → jesed (Voluntad)")
    return state


def gevura_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Guevurá: Establece límites"""
    state["constraints"] = define_constraints(state["structure"])
    state["current_sephira"] = "gevura"
    state["path_taken"].append("tiferet → gevura [fiel]")
    return state


def netsaj_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Nétsaj: Carga emocionalmente"""
    state["emotional_charge"] = add_emotion(state["balanced_decision"])
    state["current_sephira"] = "netsaj"
    state["path_taken"].append("tiferet → netsaj (Imaginativa)")
    return state


def hod_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Hod: Planifica detalladamente"""
    state["detailed_plan"] = create_detailed_plan(state["balanced_decision"])
    state["current_sephira"] = "hod"
    state["path_taken"].append("tiferet → hod (Renovadora)")
    return state


def yesod_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Yesod: Integra visión"""
    state["integrated_vision"] = integrate_vision(
        state["emotional_charge"],
        state["detailed_plan"]
    )
    state["current_sephira"] = "yesod"
    state["path_taken"].append("netsaj/hod → yesod")
    return state


def maljut_agent(state: TreeOfLifeState) -> TreeOfLifeState:
    """Agente Maljut: Genera acción concreta"""
    state["concrete_action"] = generate_action(state["integrated_vision"])
    state["current_sephira"] = "maljut"
    state["path_taken"].append("yesod → maljut (Administrativa)")
    return state


# Construcción del grafo
workflow = StateGraph(TreeOfLifeState)

# Añadir nodos (agentes)
workflow.add_node("keter", keter_agent)
workflow.add_node("jojma", jojma_agent)
workflow.add_node("bina", bina_agent)
workflow.add_node("tiferet", tiferet_agent)
workflow.add_node("jesed", jesed_agent)
workflow.add_node("gevura", gevura_agent)
workflow.add_node("netsaj", netsaj_agent)
workflow.add_node("hod", hod_agent)
workflow.add_node("yesod", yesod_agent)
workflow.add_node("maljut", maljut_agent)

# Transiciones fijas
workflow.set_entry_point("keter")
workflow.add_edge("keter", "jojma")
workflow.add_edge("jojma", "bina")
workflow.add_edge("bina", "tiferet")
workflow.add_edge("jesed", "tiferet")
workflow.add_edge("gevura", "tiferet")
workflow.add_edge("netsaj", "yesod")
workflow.add_edge("hod", "yesod")
workflow.add_edge("yesod", "maljut")
workflow.add_edge("maljut", END)

# Transiciones condicionales desde Tiféret
workflow.add_conditional_edges(
    "tiferet",
    route_from_tiferet,  # Función que retorna string con destino
    {
        "jesed": "jesed",
        "gevura": "gevura",
        "netsaj": "netsaj",
        "hod": "hod",
        "yesod": "yesod"
    }
)

# Compilar
app = workflow.compile()

6.2 Ejecución del Flujo

# Inicializar estado
initial_state = {
    "intention_raw": "Quiero crear un negocio de coaching espiritual",
    "intention_clean": "",
    "possibilities": [],
    "structure": {},
    "expansions": [],
    "constraints": [],
    "balanced_decision": "",
    "expansion_score": 0.0,
    "constraint_score": 0.0,
    "emotional_charge": "",
    "detailed_plan": {},
    "integrated_vision": "",
    "concrete_action": "",
    "current_sephira": "",
    "path_taken": [],
    "iteration_count": 0,
    "max_iterations": 20
}

# Ejecutar
final_state = app.invoke(initial_state)

# Resultado
print(final_state["concrete_action"])
# → "HOY: escribir descripción servicio (30m), mensaje a 3 contactos"

print(final_state["path_taken"])
# → ["START → keter", "keter → jojma (Ígnea)", ...]

7. Testing y Validación

7.1 Tests Unitarios por Agente

import pytest

def test_keter_extracts_intention():
    state = {"intention_raw": "Quiero hacer algo con mi vida"}
    result = keter_agent(state)
    assert result["intention_clean"] != ""
    assert len(result["intention_clean"]) < len(state["intention_raw"])


def test_jojma_generates_multiple_possibilities():
    state = {"intention_clean": "servir a otros"}
    result = jojma_agent(state)
    assert len(result["possibilities"]) >= 3
    assert all(isinstance(p, str) for p in result["possibilities"])


def test_tiferet_calculates_scores():
    state = {
        "possibilities": ["a", "b", "c"],
        "expansions": ["x", "y"],
        "constraints": []
    }
    result = tiferet_agent(state)
    assert 0 <= result["expansion_score"] <= 1
    assert 0 <= result["constraint_score"] <= 1


def test_routing_needs_expansion():
    state = {
        "expansion_score": 0.2,
        "constraint_score": 0.5,
        "iteration_count": 0
    }
    assert route_from_tiferet(state) == "jesed"


def test_routing_needs_constraints():
    state = {
        "expansion_score": 0.6,
        "constraint_score": 0.1,
        "iteration_count": 0
    }
    assert route_from_tiferet(state) == "gevura"


def test_routing_balanced_descends():
    state = {
        "expansion_score": 0.5,
        "constraint_score": 0.5,
        "emotional_charge": "passionate",
        "detailed_plan": {"week1": "action"},
        "iteration_count": 5
    }
    assert route_from_tiferet(state) == "yesod"


def test_max_iterations_forces_descent():
    state = {
        "expansion_score": 0.1,
        "constraint_score": 0.1,
        "iteration_count": 21,
        "max_iterations": 20
    }
    assert route_from_tiferet(state) == "yesod"

7.2 Tests de Integración

def test_complete_flow_terminates():
    """Verifica que todo flujo eventualmente termina"""
    initial = create_initial_state("test intention")
    final = app.invoke(initial)
    assert final["current_sephira"] == "maljut"
    assert final["concrete_action"] != ""


def test_path_is_recorded():
    """Verifica trazabilidad completa"""
    initial = create_initial_state("test")
    final = app.invoke(initial)
    assert len(final["path_taken"]) > 5
    assert "START → keter" in final["path_taken"][0]
    assert "maljut" in final["path_taken"][-1]


def test_intention_preserved():
    """Verifica que intención original no se pierde"""
    initial = create_initial_state("servir con coaching")
    final = app.invoke(initial)
    assert "servir" in final["intention_clean"].lower()
    assert "coaching" in final["concrete_action"].lower()


def test_determinism():
    """Verifica que mismo input produce mismo output"""
    initial = create_initial_state("mismo input")
    result1 = app.invoke(initial)
    result2 = app.invoke(initial)
    assert result1["concrete_action"] == result2["concrete_action"]
    assert result1["path_taken"] == result2["path_taken"]

8. Conclusión

La implementación del Árbol de la Vida como máquina de estados finitos ofrece:

Este modelo transforma la sabiduría cabalística en una arquitectura de software moderna, manteniendo la profundidad conceptual mientras se garantiza la corrección técnica.

En la siguiente sección, exploraremos las 32 Inteligencias que actúan como herramientas de transición entre estados.