Files
mission-control-v2/backend/tests/test_lucy_autonomie.py
T
HitonabiandClaude Opus 5.5 12cefb427a Welle 3 · Lucys Freiheiten je Aktionsart, Rückfragen mit „ja 7“, Lucy untersucht rote Hinweise, Wochenbericht
- services/lucy_autonomie.py: Stufe je Aktionsart (nur lesen, erst fragen, selbst handeln), Start „mehr Freiheit“;
  Meldung danach (POST /api/lucy/gehandelt)
- services/rueckfragen.py: nummerierte Rückfragen, nur Knöpfe der Oberfläche (ERLAUBT), „ja“ führt genau die
  gespeicherte Aktion aus, 24 h gültig, hinfällig wenn der Hinweis weg ist, Nachprüfung danach
- notify.sh -k: Antworttasten (Antworttastatur über den Direktweg, ohne Eingriff in Hermes)
- services/ermittlung.py: Wächter meldet rote Hinweise an Lucy; Knopf wird Rückfrage, Lucy sieht über den
  api_server nach und schickt Ursache und Weg als eine Nachricht
- services/wochenbericht.py + mc2-wochenbericht.timer (So 07:30): feste Sätze, Absatz vom Modell, offene
  App-Updates als Rückfragen
- MCP: Werkzeuge fragen die Freiheiten (auf_bitte), neu: freiheiten, rueckfragen, rueckfrage_beantworten,
  sicherheitsupdates_einspielen, snapshot_zurueckspielen, snapshots, geraet_logs, dienst_logs
- Ausführer-Aktion journal (nur lesend), POST /api/homelab/ziele/{id}/sicherheitsupdates
- Läufe des Homelabs mit flock (Oberfläche und Steward schreiben beide)
- Skill homelab-orchestrator, SOUL-Abschnitt als Kopie in deploy/nur-box

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 19:12:50 +02:00

81 lines
4.1 KiB
Python

"""Lucys Freiheiten je Aktionsart (Ausbauplan Welle 3, Punkt 14, 25.09.2026). User-Entscheid „Mehr Freiheit“: Sie startet
Dienste selbst neu, spielt Sicherheitsupdates ein und geht bei Rot auf den Snapshot zurück — mit Meldung danach; andere
Updates, Aufräumen, Modell-Tests und den Host-Neustart gibt es nur nach dem Ja des Commanders."""
import json
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from kern import einstellungen as einstellungen_mod
from services import lucy_autonomie, rueckfragen
@pytest.fixture
def daten(tmp_path, monkeypatch):
monkeypatch.setenv("MC_DATEN_DIR", str(tmp_path))
einstellungen_mod.einstellungen.cache_clear()
yield tmp_path
einstellungen_mod.einstellungen.cache_clear()
def test_start_ist_mehr_freiheit(daten):
stufen = lucy_autonomie.stufen()
assert {a for a, s in stufen.items() if s == "selbst"} == {"ermitteln", "neustart", "sicherheit", "rueckweg", "suchen"}
assert {a for a, s in stufen.items() if s == "fragen"} == {"updates", "aufraeumen", "radar", "host_neustart"}
assert lucy_autonomie.stufe("gibt-es-nicht") == "fragen" # im Zweifel nie ungefragt
def test_umstellen_und_merken(daten):
ergebnis = lucy_autonomie.setzen({"stufen": {"host_neustart": "lesen", "updates": "selbst"}})
assert ergebnis == {"ok": True, "text": "Gespeichert — Proxmox-Host neu starten: nur lesen; Andere Updates "
"einspielen: selbst handeln."}
assert lucy_autonomie.stufe("host_neustart") == "lesen" and lucy_autonomie.stufe("updates") == "selbst"
assert json.loads((daten / "lucy-autonomie.json").read_text(encoding="utf-8")) == {
"stufen": {"host_neustart": "lesen", "updates": "selbst"}}
stand = lucy_autonomie.stand()
assert stand["arten"][0]["id"] == "ermitteln" and set(stand["stufen"]) == {"lesen", "fragen", "selbst"}
host = next(a for a in stand["arten"] if a["id"] == "host_neustart")
assert host["stufe"] == "lesen" and host["standard"] == "fragen"
@pytest.mark.parametrize("eingabe, fehler", [
({}, "Es fehlt"), ({"stufen": {}}, "Es fehlt"), ("quatsch", "Es fehlt"),
({"stufen": {"loeschen": "selbst"}}, "gibt es nicht"), ({"stufen": {"updates": "immer"}}, "keine Stufe"),
])
def test_nur_bekanntes(daten, eingabe, fehler):
ergebnis = lucy_autonomie.setzen(eingabe)
assert not ergebnis["ok"] and fehler in ergebnis["detail"]
assert not (daten / "lucy-autonomie.json").exists()
def test_kaputte_datei_gilt_als_standard(daten):
(daten / "lucy-autonomie.json").write_text('{"stufen": {"updates": "immer", "neustart": "lesen"}}', encoding="utf-8")
assert lucy_autonomie.stufe("updates") == "fragen" and lucy_autonomie.stufe("neustart") == "lesen"
(daten / "lucy-autonomie.json").write_text("kein json", encoding="utf-8")
assert lucy_autonomie.stufe("neustart") == "selbst"
def test_meldung_danach(daten, monkeypatch):
gemeldet = []
monkeypatch.setattr(rueckfragen, "melden",
lambda betreff, text, knoepfe=None, dringend=False: gemeldet.append((betreff, text)))
ergebnis = lucy_autonomie.gehandelt({"was": "Hermes-Gateway neu gestartet.", "grund": "hing seit zehn Minuten",
"ergebnis": "hermes-gateway wird neu gestartet."})
assert ergebnis["ok"]
assert gemeldet == [("[Lucy selbst]", ("Hermes-Gateway neu gestartet. Warum: hing seit zehn Minuten\n"
"hermes-gateway wird neu gestartet."))]
assert not lucy_autonomie.gehandelt({"grund": "ohne was"})["ok"]
def test_schnittstelle(daten):
from routers import lucy
app = FastAPI()
app.include_router(lucy.router)
c = TestClient(app)
assert c.get("/api/lucy/autonomie").json()["arten"][1]["id"] == "neustart"
assert c.post("/api/lucy/autonomie", json={"stufen": {"radar": "selbst"}}).status_code == 200
assert lucy_autonomie.stufe("radar") == "selbst"
r = c.post("/api/lucy/autonomie", json={"stufen": {"radar": "nie"}})
assert r.status_code == 409 and "keine Stufe" in r.json()["detail"]