trading-system-docs/a5
Red Queen 968094498a feat(a5): Controlled Heartbeat & Resume v1
- a5/rq_heartbeat.py: HeartbeatStore + Heartbeat.run_tick (thin scheduler/resume layer)
- a5/rq_heartbeat_cli.py: status/tick/enable/disable/resume/approve/deny/priority
- a5/test_a5.py: 31 deterministic tests (tick-lock incl. ownership, eligibility, kill-switch, approval, circuit, git-conflict, bounded single A4)
- a5/DESIGN.md, a5/README.md, a5/scripts/a5_heartbeat_tick.sh
- a2/rq_mission.py: add read-only mission_list() for A5 enumeration (additive)
- Fresh checker: PASS after tick-lock ownership repair (Regressionschutz lock_owned)
2026-08-24 23:04:16 +00:00
..
scripts feat(a5): Controlled Heartbeat & Resume v1 2026-08-24 23:04:16 +00:00
DESIGN.md feat(a5): Controlled Heartbeat & Resume v1 2026-08-24 23:04:16 +00:00
README.md feat(a5): Controlled Heartbeat & Resume v1 2026-08-24 23:04:16 +00:00
rq_heartbeat.py feat(a5): Controlled Heartbeat & Resume v1 2026-08-24 23:04:16 +00:00
rq_heartbeat_cli.py feat(a5): Controlled Heartbeat & Resume v1 2026-08-24 23:04:16 +00:00
test_a5.py feat(a5): Controlled Heartbeat & Resume v1 2026-08-24 23:04:16 +00:00

Red Queen — A5: Controlled Heartbeat & Resume (V1)

Der Controlled Heartbeat & Resume verbindet den A4 Bounded Orchestrator mit einem dünnen Scheduling-/Resume-Layer (Heartbeat), sodass eine längere Mission über mehrere getrennte, sichere, restart-feste Arbeitszyklen fortgesetzt werden kann — ohne unkontrollierten Dauer-LLM-Loop.

Der Heartbeat ist NICHT der Orchestrator und keine neue Mission-Engine:

  • A2 (missions.db) bleibt autoritativ für Mission-/WP-State.
  • A3 (safety.db) bleibt verbindliche Safety-Decision (Circuit, Evaluate, Redact).
  • A4 bleibt die Orchestrierung (run_bounded = garantiert endender Zyklus).
  • A5 ist eine reine, inaktive Scheduling-/Resume-Schicht, die pro Tick GENAU EINEN bounded A4-Zyklus anstößt, das Ergebnis persistiert und sofort endet. Kein while-True, kein Daemon, kein self-reschedule.
SCHEDULER (Hermes Cron) → Heartbeat.run_tick()
  → Run-ID (Idempotenz) → Kill-Switch-Gate → Tick-Lock
  → Mission-Eligibility (inkl. Circuit + Resume-Pending)
    → A3 check_safety_state → optional Git-Preflight → Approval-Gate
      → GENAU EIN A4 run_bounded(max_steps=1)
        → Ergebnis persistieren → Lock freigeben → EXIT

Integrations (verified from source)

  • A2 MissionStore (a2/rq_mission.py, missions.db):
    • mission_list() [NEW, read-only, additiv — A5-Enumeration]
    • mission_read(id), mission_state(id), wp_state(id)
    • Transitionen: mission_transition, mission_pause, mission_resume, mission_complete, wp_transition, wp_complete.
  • A3 SafetyStore (a3/rq_safety.py, safety_db):
    • check_safety_state(mid, wp) — fail-closed STATE_INCONSISTENT
    • evaluate_next_action(mid, wp, is_mutating, persist), circuit_state, open_circuit, attempts, safety_evidence, redact_secret.
  • A4 Orchestrator (a4/rq_orchestrator.py):
    • run_bounded(mission_id, max_steps=1, actor) — EXACTLY-N bounded steps, garantiertes Ende. Heartbeat ruft DAS GENAU EINMAL pro Tick.
  • Hermes native Cron: no_agent, executions.db, .tick.lock, context_from, workdir, delivery — die bevorzugte Scheduling-Plattform (kein zweiter Scheduler).

Eigene Registry (A5-spezifisch, heartbeat.db)

A5 führt keine neue Missions-/Safety-DB, sondern nur eine schlanke Registry für Heartbeat-eigene Steuerung:

  • kill_switchAUTONOMOUS_EXECUTION_ENABLED, Default OFF. OFF → run_tick liefert HB_KILL_SWITCH_OFF vor jeder A4-Mutation. status/health bleiben read-only.
  • lockEIN-Tick-Lock (idempotent). acquire_lockok|locked|recover. Stale nach TICK_LOCK_STALE_SECONDS (600s).
  • run_id-Ledger + tick_log — jede Tick-Ausführung wird persistiert (Idempotenz).
  • approval_gates, resume_pending, notification_dedup, priority.

Restart-Festigkeit: Alle DBs (missions, safety, heartbeat) liegen auf persistenter Volume, nicht process-local. Ein frischer Prozess liest den State neu; neue Run-ID, keine Doppel-/Neu-Ausführung, kein verlorener Pending-State.


A5-Result-Codes (§10)

HB_NO_ACTIVE_MISSION, HB_MISSION_NOT_ELIGIBLE, HB_SAFETY_BLOCKED,
HB_STATE_CONFLICT, HB_NO_RUNNABLE_WORK, HB_BOUNDED_RUN_COMPLETE,
HB_MISSION_COMPLETED, HB_APPROVAL_REQUIRED, HB_ESCALATED, HB_CIRCUIT_OPEN,
HB_TIMEOUT, HB_INTERNAL_ERROR,
HB_LOCKED, HB_KILL_SWITCH_OFF, HB_PAUSED, HB_CANCELLED,
HB_GIT_CONFLICT, HB_RECOVERY_REQUIRED

health()/status sind read-only und immer erlaubt. Jeder gescheiterte Gate liefert einen stabilen HB_*-Code (fail-closed, keine partielle Mutation).


CLI

python3 a5/rq_heartbeat_cli.py — deterministisch, kein Loop, kein Root:

status                 Kill-Switch, letzter Tick, Registry-Infos
tick [--mission ID]    EIN bounded Heartbeat-Zyklus (ohne --execute read-only)
enable                 Kill-Switch ON (bewusst; erlaubt A4-Mutation)
disable                Kill-Switch OFF (Fail-closed)
resume --mission ID    PAUSED-Mission explizit als resume-fähig markieren
approve --gate ID      Approval-Gate bewilligen
deny    --gate ID      Approval-Gate ablehnen
priority --mission --prio N

--execute ist ein globales Flag (vor dem Subcommand): ohne ist tick read-only, mit injiziert es einen echten Orchestrator und erlaubt einen A4-Mutation.


Cron-Integration (Hermes native)

cron:
  # One-Shot oder wiederkehrend, no_agent=True, Script aus $HERMES_HOME/scripts
  script: a5_heartbeat_tick.sh   # ruft EINEN bounded Tick; kein Loop

One-Shot-Jobs werden nach Ausführung automatisch entfernt → es bleibt kein unkontrollierter Dauer-Job zurück (hermes cron list = 0). Der Tick läuft mit no_agent über die Heartbeat-Library, ohne eigenständigen LLM-Loop.


Test Harness

python3 a5/test_a5.py — isolierte, deterministische Tests (temp-DBs, kein Netz, kein echter A4-Dispatch außer einem bounded real-Orchestrator-Test). Exit-Code 0 = PASS. Deckt: Kill-Switch off/on, Tick-Lock (overlap → HB_LOCKED und Lock-Erhalt), Lock-Release nach Owner-Tick, Eligibility (cancelled/paused/resumable), Priorität, GENAU EIN bounded A4-Call, No-Runnable, Approval-Block/Grant/Resume, Circuit-Block, Git-Konflikt, unbekannte Mission, read-only health, bounded-real-Orchestrator-Contract.

Regressions: a2/test_a2.py (61), a3/test_a3.py (69), a4/test_a4.py (83).


Fail-closed & Approval

  • mission_completion_gate(..., final_review_pass=False) — A5 übergibt standardmäßig Falsekein autonomes Final-Review/Auto-Complete in V1.
  • Approval-Gates persistieren in der Registry; erst nach approve wird die Mission wieder runnable.
  • open_circuit (A3) ist keyword-only nach scope_type/scope_id: open_circuit("MISSION", mid, trigger=..., reason=...).

Known Limitations

  • A5 selbst startet keine echte A4-Mutation außerhalb eines ausdrücklichen --execute-Ticks. Produktiver Heartbeat/Cron ist erst nach expliziter Freigabe (Kill-Switch) aktiv; Default OFF.
  • Kein automatisches Rain; kein Self-Improvement-Automation; kein unkontrollierter Dauerlauf.