- 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) |
||
|---|---|---|
| .. | ||
| scripts | ||
| DESIGN.md | ||
| README.md | ||
| rq_heartbeat.py | ||
| rq_heartbeat_cli.py | ||
| test_a5.py | ||
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-closedSTATE_INCONSISTENTevaluate_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_switch—AUTONOMOUS_EXECUTION_ENABLED, Default OFF. OFF →run_tickliefertHB_KILL_SWITCH_OFFvor jeder A4-Mutation.status/healthbleiben read-only.lock— EIN-Tick-Lock (idempotent).acquire_lock→ok|locked|recover. Stale nachTICK_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äßigFalse→ kein autonomes Final-Review/Auto-Complete in V1.- Approval-Gates persistieren in der Registry; erst nach
approvewird 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.