From 6904bcbfb007a1dc06b6a706115d57e0fbdb01ef Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Sat, 26 Sep 2026 09:24:13 +0200 Subject: [PATCH] =?UTF-8?q?Hermes-Update:=20neue=20Commits=20im=20flachen?= =?UTF-8?q?=20Klon=20richtig=20z=C3=A4hlen=20(281=20statt=2042=20044);=20W?= =?UTF-8?q?ochenbericht=20duzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - maintenance._hermes_bereich: --ancestry-path, wenn HEAD Vorfahr von origin/ ist (seit dem Paketmanager ist der Checkout ein flacher Klon); sonst der einfache Bereich wie bisher - Wochenbericht: Lucy duzt, nennt nur als Aufgabe, was ausdrücklich auf den Commander wartet; ungetestete Radar-Kandidaten testet das Radar nachts selbst Co-Authored-By: Claude Opus 5.5 --- backend/services/maintenance.py | 17 +++++++++++++++-- backend/services/wochenbericht.py | 12 +++++++----- backend/tests/test_wartung.py | 25 +++++++++++++++++++++++++ backend/tests/test_wochenbericht.py | 3 ++- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/backend/services/maintenance.py b/backend/services/maintenance.py index 61c1910..655dd1b 100644 --- a/backend/services/maintenance.py +++ b/backend/services/maintenance.py @@ -191,6 +191,19 @@ def _swap_update_available() -> bool: _comp_cache = {"ts": 0.0, "data": []} +def _hermes_bereich(path: str, branch: str) -> list[str]: + """Der Bereich der neuen Commits für git rev-list/log. Der Hermes-Checkout ist seit dem Paketmanager (25.09.2026) + ein flacher Klon: HEAD..origin/main zählte dann die ganze Vorgeschichte hinter der flachen Grenze mit (26.09.: + 42 044 statt 281). Mit --ancestry-path zählen nur Nachfahren von HEAD. Ist HEAD kein Vorfahr (Geschichte oben + umgeschrieben), bleibt es beim einfachen Bereich — sonst sähe die Box gar kein Update mehr.""" + try: + vorfahr = subprocess.run(["git", "-C", path, "merge-base", "--is-ancestor", "HEAD", f"origin/{branch}"], + capture_output=True, text=True, timeout=8).returncode == 0 + except (OSError, subprocess.SubprocessError): + vorfahr = False + return ["--ancestry-path", f"HEAD..origin/{branch}"] if vorfahr else [f"HEAD..origin/{branch}"] + + def _hermes_agent_update() -> dict: """Hermes-Agent wird aus **git** aktualisiert (CLI `hermes update` = git pull origin ). Darum HEAD vs. origin/ prüfen (fetch + behind-count) — NICHT GitHub-Releases: die @@ -209,7 +222,7 @@ def _hermes_agent_update() -> dict: capture_output=True, text=True, timeout=60) info["reachable"] = (fetch.returncode == 0) if fetch.returncode == 0: - cnt = subprocess.run(["git", "-C", path, "rev-list", "--count", f"HEAD..origin/{branch}"], + cnt = subprocess.run(["git", "-C", path, "rev-list", "--count", *_hermes_bereich(path, branch)], capture_output=True, text=True, timeout=8) behind = int(cnt.stdout.strip() or "0") if cnt.returncode == 0 else 0 info["behind"] = behind @@ -534,7 +547,7 @@ def hermes_update_details() -> dict: subprocess.run(["git", "-C", path, "fetch", "-q", "origin", branch], capture_output=True, text=True, timeout=60) log = subprocess.run(["git", "-C", path, "log", "--pretty=format:%h\x1f%s\x1f%cr", - f"HEAD..origin/{branch}"], capture_output=True, text=True, timeout=10) + *_hermes_bereich(path, branch)], capture_output=True, text=True, timeout=10) commits = [] for line in (log.stdout or "").splitlines(): parts = line.split("\x1f") diff --git a/backend/services/wochenbericht.py b/backend/services/wochenbericht.py index 4423831..04fc1e3 100644 --- a/backend/services/wochenbericht.py +++ b/backend/services/wochenbericht.py @@ -39,10 +39,11 @@ BAUSTEIN = {"app": "App", "os": "Pakete", "pakete": "Pakete", "docker": "Docker" "kernel": "alte Kernel", "neustart": "Neustart"} NICHT_GLATT = {"zurueckgerollt": "zurückgerollt", "festgehalten": "festgehalten", "fehler": "gescheitert"} PROSA = """Du bist Lucy, die Systemadministratorin dieses Homelabs, und schreibst dem Commander seinen Wochenbericht. -Schreib drei bis fünf Sätze Fließtext: wie die Woche lief, was wichtig ist und was er tun sollte. Beginne mit \ -„Commander,“. Knapp, sachlich, ohne Emojis, ohne Ausrufezeichen, ohne Aufzählung. Nimm nur, was in den Fakten steht — \ -keine Zahl, kein Name, kein Ereignis, das dort fehlt. Die Fakten und die Rückfragen stehen unter deinem Absatz ohnehin \ -noch einmal; wiederhole sie nicht Punkt für Punkt. +Schreib drei bis fünf Sätze Fließtext: wie die Woche lief und was wichtig ist. Beginne mit „Commander,“ und sprich ihn \ +mit „du“ an, nie mit „Sie“. Knapp, sachlich, ohne Emojis, ohne Ausrufezeichen, ohne Aufzählung. Nimm nur, was in den \ +Fakten steht — keine Zahl, kein Name, kein Ereignis, das dort fehlt. Zu tun hat er nur, was dort ausdrücklich auf ihn \ +wartet („wartet auf deine Entscheidung“); alles andere erledigen der Orchestrator und du selbst. Die Fakten und die \ +Rückfragen stehen unter deinem Absatz noch einmal; wiederhole sie nicht Punkt für Punkt. Fakten dieser Woche: {fakten}""" @@ -237,7 +238,8 @@ def _radar(f: dict) -> str | None: if bestanden: teile.append(f"bestanden und wartet auf deine Entscheidung: {_liste(bestanden)}") if wartend: - teile.append(f"{wartend} {'Kandidat wartet' if wartend == 1 else 'Kandidaten warten'} auf den Test") + teile.append(f"{wartend} {'Kandidat ist' if wartend == 1 else 'Kandidaten sind'} noch ungetestet (das Radar " + "testet nachts selbst)") return "; ".join(teile) or None diff --git a/backend/tests/test_wartung.py b/backend/tests/test_wartung.py index cbb695e..73c860f 100644 --- a/backend/tests/test_wartung.py +++ b/backend/tests/test_wartung.py @@ -159,3 +159,28 @@ def test_zurueckgehaltene_pakete_sind_kein_update(monkeypatch): monkeypatch.setattr(maintenance.subprocess, "run", lambda befehl, **kw: subprocess.CompletedProcess(befehl, 100, stdout="", stderr="")) assert maintenance._os_upgradable() == 0 and "Paketliste nicht lesbar" in maintenance.PRUEF_FEHLER["os"] + + +def test_hermes_commits_im_flachen_klon(monkeypatch, tmp_path): + """26.09.2026: Der Hermes-Checkout ist ein flacher Klon — HEAD..origin/main zählte 42 044 statt 281 neuer Commits. + Ist HEAD ein Vorfahr, zählt nur der Weg von HEAD aus (--ancestry-path); sonst der einfache Bereich.""" + monkeypatch.setattr(maintenance.system, "find_hermes_agent_git", lambda: {"path": str(tmp_path), "hash": "59004a6"}) + aufrufe: list[list[str]] = [] + vorfahr = {"code": 0} + + def run(befehl, **kw): + aufrufe.append(befehl) + if "--is-ancestor" in befehl: + return subprocess.CompletedProcess(befehl, vorfahr["code"], stdout="", stderr="") + if "--count" in befehl: + return subprocess.CompletedProcess(befehl, 0, stdout="281\n" if "--ancestry-path" in befehl else "42044\n", + stderr="") + return subprocess.CompletedProcess(befehl, 0, stdout="main\n" if "--abbrev-ref" in befehl else "d0288be\n", + stderr="") + + monkeypatch.setattr(maintenance.subprocess, "run", run) + assert maintenance._hermes_agent_update()["behind"] == 281 + vorfahr["code"] = 1 + assert maintenance._hermes_agent_update()["behind"] == 42044 + zaehlen = [b for b in aufrufe if "--count" in b] + assert zaehlen[0][-2:] == ["--ancestry-path", "HEAD..origin/main"] and zaehlen[1][-1] == "HEAD..origin/main" diff --git a/backend/tests/test_wochenbericht.py b/backend/tests/test_wochenbericht.py index ac3ac7e..bc7bdd3 100644 --- a/backend/tests/test_wochenbericht.py +++ b/backend/tests/test_wochenbericht.py @@ -85,7 +85,8 @@ def test_feste_saetze(): "Sicherungen: Stufe gelb; zu alt oder fehlend: Arcane; Probe-Wiederherstellung gescheitert: NetBird.", "Zertifikate: mc.example: wird nicht erneuert, noch 2 Tage gültig.", "Lücken-Scan: immich (3 kritisch).", - "Modell-Radar: bestanden und wartet auf deine Entscheidung: Qwen4-30B; 2 Kandidaten warten auf den Test.", + ("Modell-Radar: bestanden und wartet auf deine Entscheidung: Qwen4-30B; 2 Kandidaten sind noch ungetestet " + "(das Radar testet nachts selbst)."), "Lucy: 1× selbst gehandelt; 1× auf deine Bitte; 2 Rückfragen beantwortet oder abgelaufen, davon 1× ja.", ]