trading-system-docs/a2/rq_state_machine.py
Red Queen dbbbb1dddc feat(a2): persistent mission state & state machine
RED QUEEN BUILD PHASE A2: Mission-State- und Work-Package-State-Machine.
Minimaler Missions-Metadata-Layer (missions.db) auf nativer Hermes-Kanban-Basis
(KanbanMirror best effort). Deterministische Validierung, Idempotenz,
STATE_ERROR fail-closed, Restart-Persistenz. 61 deterministische Tests PASS.
Keine autonome Orchestrierung/Loops/Cron.
2026-08-24 20:18:32 +00:00

121 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""
Red Queen — A2: Deterministische Zustandsmaschinen (MISSION + WORK PACKAGE).
Single source of truth fuer alle erlaubten/verbotenen Transitions, gemaeß
`red-queen-architecture/MISSION_STATE_MACHINE.md` (autoritativer Vertrag).
Dieses Modul enthaelt KEINE Persistenz und KEINE Orchestrierung — nur die
reinen State-Mengen und Transition-Tabellen. Die Anwendung (Persistenz,
Validierung, Kanban-Mirror) liegt in `rq_mission.py`.
Transitions sind deterministisch: fuer ein gegebenes (von, nach) Paar gibt es
genau eine Antwort (erlaubt / verboten).
"""
from __future__ import annotations
from typing import Dict, FrozenSet, Set, Tuple
# --------------------------------------------------------------------------- #
# State-Mengen
# --------------------------------------------------------------------------- #
MISSION_STATES: FrozenSet[str] = frozenset(
{
"CREATED",
"PLANNING",
"READY",
"RUNNING",
"REVIEW",
"COMPLETED",
"BLOCKED",
"PAUSED",
"FAILED",
"CANCELLED",
"ESCALATED",
}
)
WP_STATES: FrozenSet[str] = frozenset(
{
"TODO",
"READY",
"IN_PROGRESS",
"CHECKING",
"DONE",
"FAILED",
"BLOCKED",
"ESCALATED",
}
)
# Endzustaende (keine Reaktivierung ohne Neuanlage).
MISSION_TERMINAL: FrozenSet[str] = frozenset({"FAILED", "CANCELLED"})
WP_TERMINAL: FrozenSet[str] = frozenset({"FAILED"}) # DONE ist terminal im
# Sinne "nicht mehr normal weiter", aber idempotent akzeptiert.
# ---------------------------------------------------------------------------
# Transition-Tabellen — MISSION
# ---------------------------------------------------------------------------
# MISSION_STATE_MACHINE.md §4 (Mission): (von, nach) -> erlaubt
MISSION_TRANSITIONS: Set[Tuple[str, str]] = {
("CREATED", "PLANNING"),
("PLANNING", "READY"),
("PLANNING", "BLOCKED"),
("READY", "RUNNING"),
("RUNNING", "REVIEW"),
("REVIEW", "COMPLETED"),
("REVIEW", "RUNNING"),
("RUNNING", "PAUSED"),
("PAUSED", "RUNNING"),
("RUNNING", "BLOCKED"),
("BLOCKED", "PAUSED"),
("BLOCKED", "RUNNING"),
("BLOCKED", "ESCALATED"),
("PAUSED", "CANCELLED"),
("RUNNING", "FAILED"),
("RUNNING", "CANCELLED"),
("BLOCKED", "CANCELLED"),
("ESCALATED", "RUNNING"),
("ESCALATED", "CANCELLED"),
("ESCALATED", "COMPLETED"),
}
# ---------------------------------------------------------------------------
# Transition-Tabellen — WORK PACKAGE
# ---------------------------------------------------------------------------
WP_TRANSITIONS: Set[Tuple[str, str]] = {
("TODO", "READY"),
("READY", "IN_PROGRESS"),
("IN_PROGRESS", "CHECKING"),
("CHECKING", "DONE"),
("CHECKING", "IN_PROGRESS"),
("IN_PROGRESS", "FAILED"),
("IN_PROGRESS", "BLOCKED"),
("BLOCKED", "IN_PROGRESS"),
("BLOCKED", "ESCALATED"),
("ESCALATED", "IN_PROGRESS"),
("ESCALATED", "FAILED"),
}
# ---------------------------------------------------------------------------
# API
# ---------------------------------------------------------------------------
def is_mission_state(state: str) -> bool:
return state in MISSION_STATES
def is_wp_state(state: str) -> bool:
return state in WP_STATES
def mission_transition_allowed(current: str, target: str) -> bool:
"""Deterministische Antwort, ob (current -> target) erlaubt ist."""
return (current, target) in MISSION_TRANSITIONS
def wp_transition_allowed(current: str, target: str) -> bool:
"""Deterministische Antwort, ob (current -> target) erlaubt ist."""
return (current, target) in WP_TRANSITIONS