generated from coulomb/repo-seed
feat(WARDEN-WP-0021): T3-T5 — visibility, approve loop, runbook (scheduled worker complete)
T4 (review→send loop): conservative tick persists structured drafts to state_dir/worker-drafts.json; `warden worker drafts` lists them, `warden worker approve <id> [--body …]` sends the reviewed draft as the reply + marks read + drops it. Escalated plans persist no draft. Live-verified end-to-end. T3 (visibility): `warden worker status` (pending drafts, triage count, last digest, timer state); best-effort notify-send nudge in the tick when drafts are pending. T5: wiki/playbooks/scheduled-worker.md (enable/disable, the approve loop, failure modes, conservative-only posture) + SCOPE note. WARDEN-WP-0021 finished: the conservative worker now runs on a systemd --user timer (enabled, every 15 min), triages new inbox messages into drafts you approve with one command, degrades gracefully, and stops with one command. 249 tests, lint clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -206,6 +206,46 @@ def test_run_conservative_drafts_no_sends_and_dedups(tmp_path):
|
||||
assert not any(c[0] == "progress" for c in hub2.calls)
|
||||
|
||||
|
||||
# --- approve loop (WP-0021 T4) ------------------------------------------------
|
||||
|
||||
def test_conservative_persists_draft_and_approve_sends(tmp_path):
|
||||
from warden.worker import approve_draft, list_drafts, load_drafts
|
||||
hub = _FakeHub()
|
||||
p = _plan([PlannedAction(kind="route_answer", summary="a", payload={"answer": "the answer"})])
|
||||
run_conservative([p], hub, state_dir=tmp_path)
|
||||
drafts = load_drafts(tmp_path)
|
||||
assert "m1" in drafts and drafts["m1"]["body"] == "the answer"
|
||||
assert "m1" in list_drafts(tmp_path)
|
||||
# approve → sends the reply + marks read + drops the draft
|
||||
hub2 = _FakeHub()
|
||||
out = approve_draft("m1", hub2, state_dir=tmp_path)
|
||||
assert any(c[0] == "reply" and c[3] == "the answer" for c in hub2.calls)
|
||||
assert any(c[0] == "mark_read" for c in hub2.calls)
|
||||
assert "m1" not in load_drafts(tmp_path)
|
||||
assert "sent reply" in out
|
||||
|
||||
|
||||
def test_approve_body_override(tmp_path):
|
||||
from warden.worker import approve_draft, save_drafts
|
||||
save_drafts(tmp_path, {"m9": {"to_agent": "bob", "subject": "Re: x", "body": "orig", "thread_id": "t"}})
|
||||
hub = _FakeHub()
|
||||
approve_draft("m9", hub, state_dir=tmp_path, body_override="edited")
|
||||
assert any(c[0] == "reply" and c[3] == "edited" for c in hub.calls)
|
||||
|
||||
|
||||
def test_approve_missing_draft(tmp_path):
|
||||
from warden.worker import approve_draft
|
||||
out = approve_draft("nope", _FakeHub(), state_dir=tmp_path)
|
||||
assert "no pending draft" in out
|
||||
|
||||
|
||||
def test_escalated_plan_persists_no_draft(tmp_path):
|
||||
a = PlannedAction(kind="reply", summary="x", risk="escalate", reason="secret")
|
||||
run_conservative([_plan([a])], _FakeHub(), state_dir=tmp_path)
|
||||
from warden.worker import load_drafts
|
||||
assert load_drafts(tmp_path) == {}
|
||||
|
||||
|
||||
# --- executor (T3) -----------------------------------------------------------
|
||||
|
||||
class _FakeHub:
|
||||
|
||||
Reference in New Issue
Block a user