trading-system-docs/a5/DESIGN.md
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

34 lines
2.4 KiB
Markdown

# A5 DESIGN — CONTROLLED HEARTBEAT & RESUME v1
## Integrations (verified from source)
- **A2 `MissionStore`** (`a2/rq_mission.py`, `missions.db`):
- `mission_list()` [NEW, read-only, added for A5] — enumerate missions.
- `mission_read(id)` -> dict with `work_packages`, `dependencies`, `state`.
- `mission_state(id)`, `wp_state(id)`.
- Transitions: `mission_transition(id,target,actor,evidence)`, `mission_pause`, `mission_resume`, `mission_complete`, `wp_transition`, `wp_complete`.
- Transition tables in `a2/rq_state_machine.py`: eligible mission states {READY,RUNNING,REVIEW,PAUSED-resume-capable}; PAUSED->RUNNING allowed; BLOCKED->IN_PROGRESS (wp) allowed; REVIEW->RUNNING allowed.
- **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)` — decision + circuit.
- `circuit_state(scope_type,scope_id)`, `open_circuit`, `attempts`, `attempts_count`, `safety_evidence`, `redact_secret`.
- **A4 `Orchestrator`** (`a4/rq_orchestrator.py`):
- `__init__(mission_db, safety_db, child_dispatcher=None, max_bounded_runtime=...)`.
- `run_bounded(mission_id, max_steps=1, actor)` — EXACTLY-N bounded steps, guarantees return. Without child_dispatcher returns dispatch contracts; with dispatcher runs full Maker+Checker.
- `attempt_mission_complete(mission_id, final_review_pass=...)`.
- `run_one_step` = 1 child cycle. A4 has own limits (no loop).
- **Hermes native cron**: `.tick.lock`, `executions.db`, no_agent, workdir, delivery. Baseline regression A2=61, A3=69, A4=83 PASS.
## 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, plus HB_LOCKED, HB_KILL_SWITCH_OFF,
HB_PAUSED, HB_CANCELLED, HB_GIT_CONFLICT, HB_RECOVERY_REQUIRED.
## Key invariants (spec §5,§9,§18,§25,§29,§30)
- A5 is a thin layer: never fabricates states/retries/circuits. Delegates to A2/A3/A4.
- Exactly ONE A4 `run_bounded(max_steps=1)` per tick per mission; MAX 1 mission per tick.
- No while-true, no self-reschedule, no background child dependency.
- Kill switch default OFF; blocks all mutation, read-only health allowed.
- Fail-closed: any gate failure -> NO mutation, stable result code.
- Dedup notifications by (mission, reason_code, evidence_hash).