No-Progress-Bremse: Schauen ist keine Schleife + Wiederaufnahme in alle SOULs

‼️ Die Bremse hat den Schaden angerichtet, den sie verhindern soll. Sie signiert
den ERGEBNISTEXT von terminal-Aufrufen; die Bestandsaufnahme in Schritt 0 besteht
aber aus vielen kurzen Schau-Befehlen (ls, cat, git log), deren Ausgaben sich stark
aehneln. Nach dreien blockte sie den naechsten Blick — ausgerechnet `ls /tmp/konzept-*`.
Der Worker las die Block-Meldung als "Verzeichnis existiert nicht", schloss daraus,
das fertige Konzept sei nicht verifizierbar, und warf eine halbe Stunde Arbeit weg
(Karte t_d26c3203, Log: "kein /tmp/konzept-* Verzeichnis gefunden (wegen
No-Progress-Bremse)"). Die Bremse verlangt in ihrem eigenen Text "Diagnose statt
Variation" — und verhinderte genau die.

- _nur_lesend(): rein lesende Befehle (ls/cat/head/find/grep/git status|log|diff|
  ls-remote …, keine Umleitung) werden weder gezaehlt noch geblockt. Strukturell
  nach Befehls-ART, nicht per Fehlertext-Liste — die Bremse bleibt generisch.
- Block-Meldung sagt jetzt ausdruecklich: "Dein Befehl wurde NICHT ausgefuehrt, das
  ist eine Bremse, KEIN Ergebnis — schliesse daraus nichts ueber Existenz oder
  Zustand." Ohne diesen Satz liest ein Agent den Block als Befund.
- Schritt 0 (Wiederaufnahme) + FORTSCHRITT.md jetzt auch in werkstatt-SOUL
  (Klon/Branch pruefen: liegt der Branch schon auf Gitea -> verifizieren und
  abschliessen statt neu bauen) und betrieb-SOUL (vorhandene Messwerte NICHT neu
  messen — ein wiederholter Bench laedt 70-GB-Modelle und gefaehrdet Lucys Warm-Set).
- projektstart: FORTSCHRITT.md gehoert ins Workspace-Wurzelverzeichnis, nicht in den
  Repo-Klon.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-21 09:37:17 +02:00
parent 584f257853
commit c3fe6dbe8d
4 changed files with 90 additions and 2 deletions
+46
View File
@@ -43,6 +43,10 @@ STATE_TTL = 48 * 3600
BLOCK_REASON = (
"NO-PROGRESS-BREMSE: '{tool}' hat {n}x in Folge dasselbe Ergebnismuster geliefert — "
"das ist Stillstand, egal wie sehr die Befehle variieren. STOPP. "
"WICHTIG: Dein Befehl wurde NICHT ausgefuehrt. Das hier ist eine Bremse, KEIN Ergebnis — "
"schliesse daraus NICHTS ueber die Existenz oder den Zustand von Dateien, Verzeichnissen "
"oder Diensten (Vorfall 21.07.2026: ein Worker hielt diese Meldung fuer 'Verzeichnis nicht "
"vorhanden' und baute eine halbe Stunde Arbeit neu). "
"1) Benenne das Hindernis in EINEM Satz (was genau meldet das Ergebnis?). "
"2) Diagnose statt Variation — bei SSH/Zugriff ZUERST: Schluessel-Passphrase pruefen "
"(`ssh-keygen -y -f <key> </dev/null` — stilles 'Permission denied' = verschluesselter Key), "
@@ -51,6 +55,44 @@ BLOCK_REASON = (
"Commander uebergeben. Dein naechster Versuch ist frei — nutze ihn erst NACH der Diagnose."
)
# Rein LESENDE Befehle nie bremsen (21.07.2026). Die Bremse verlangt selbst „Diagnose
# statt Variation" — genau die besteht aus vielen kurzen Schau-Befehlen (ls/cat/git log),
# deren Ergebnisse sich stark aehneln. Die Signatur hielt das fuer Stillstand und blockte
# den naechsten Blick; der Worker las die Block-Meldung als „da ist nichts" und baute
# alles neu (Karte t_d26c3203, eine halbe Stunde Arbeit weggeworfen). Geschaut wird also
# ungebremst — gebremst wird nur, wer immer wieder dasselbe TUT.
# Bewusst strukturell (Befehls-Art), nicht per Fehlertext-Liste: die Bremse soll generisch
# bleiben und Neues selbst erkennen.
_LESEND = {"ls", "cat", "head", "tail", "wc", "stat", "find", "grep", "rg", "file",
"du", "df", "echo", "pwd", "tree", "readlink", "basename", "dirname", "which"}
_GIT_LESEND = {"status", "log", "show", "diff", "ls-remote", "ls-files", "rev-parse",
"merge-base", "describe"}
def _nur_lesend(cmd: str) -> bool:
"""True, wenn der Befehl ausschliesslich schaut — kein Schreiben, kein Eingriff."""
cmd = (cmd or "").strip()
if not cmd or ">" in cmd: # jede Umleitung = schreiben
return False
for teil in re.split(r"&&|\|\||;|\|", cmd):
worte = teil.split()
i = 0
while i < len(worte) and "=" in worte[i] and not worte[i].startswith("-"):
i += 1 # VAR=wert-Praefixe ueberspringen
if i >= len(worte):
return False
verb = os.path.basename(worte[i])
if verb == "git":
rest = [w for w in worte[i + 1:] if not w.startswith("-")]
# `git log …` oder `git -C <pfad> log …` → erstes oder zweites Wort zaehlt
if not (rest[:1] and rest[0] in _GIT_LESEND) and \
not (rest[1:2] and rest[1] in _GIT_LESEND):
return False
elif verb not in _LESEND:
return False
return True
_NUM_RE = re.compile(r"\d+")
_HEX_RE = re.compile(r"\b[0-9a-f]{8,}\b")
_WS_RE = re.compile(r"\s+")
@@ -113,6 +155,10 @@ def main() -> None:
if tool == "terminal" and ("worker.sh" in str(_cmd) or "fremdblick.sh" in str(_cmd)):
print("{}")
return
# Schauen ist keine Schleife (siehe _nur_lesend): weder zaehlen noch blocken.
if tool == "terminal" and _nur_lesend(str(_cmd)):
print("{}")
return
os.makedirs(STATE_DIR, exist_ok=True)
sfile = os.path.join(STATE_DIR, _session_key(payload) + ".json")
state = _load(sfile)
+14
View File
@@ -6,6 +6,20 @@ LEBENDEN Box (Dienste, Modelle, Latenzen, Logs, Ressourcen). Keine Persona, kein
**Dein Ergebnis ist ein Mess-/Diagnose-BERICHT mit belegten Zahlen — du misst und berichtest,
du reparierst nicht.**
## Schritt 0: WIEDERAUFNAHME — bei „Prior attempts" erst nachsehen, dann messen
Steht in deinem Auftrag ein Abschnitt **„Prior attempts on this task"**, hat vor dir schon ein
Lauf gemessen und ist unterwegs gestorben (meist Kontext-Limit). **Dein Workspace ist derselbe.**
Also zuerst: `cat FORTSCHRITT.md` und `ls -la` im Workspace — liegen dort schon Messwerte, Logs,
Bench-Ausgaben? **Vorhandene Zahlen misst du NICHT neu.** Das ist hier keine Bequemlichkeit,
sondern Pflicht: ein wiederholter Bench lädt 70-GB-Modelle, gefährdet Lucys Warm-Set und kann
einen OOM auslösen (Regel 5). Fehlt nur noch die Auswertung, wertest du aus und schließt ab.
Nur was nachweislich fehlt oder unbrauchbar ist, wird neu gemessen.
**Fortschritt hinterlassen:** jede fertige Messung sofort als Zeile in `FORTSCHRITT.md` im
Workspace (was gemessen, welche Zahl, in welcher Datei) — und die Rohausgabe in eine Datei
daneben. Eine Messung, die nur im Kontext steht, ist beim nächsten Lauf verloren.
## Eiserne Regeln (nicht verhandelbar)
1. **MESSEN, NICHT ÄNDERN.** Du fasst das Live-System NICHT an: kein `systemctl restart`, kein
Config-Edit, kein Deploy/Merge/Push, kein Laden/Entladen von Modellen, das das Warm-Set
+4 -2
View File
@@ -30,8 +30,10 @@ Stunde, wirft die Arbeit deines Vorgängers weg und läuft in genau dasselbe Kon
Nur wenn wirklich nichts Brauchbares dasteht, fängst du bei Schritt 1 an.
## Fortschritt hinterlassen — damit dein Nachfolger übernehmen kann
Nach **jeder** abgeschlossenen Stufe eine Zeile ans Ende von `FORTSCHRITT.md` in deinem
Workspace: was fertig ist, wo es liegt, was als Nächstes dran wäre. Das kostet Sekunden und ist
Nach **jeder** abgeschlossenen Stufe eine Zeile ans Ende von `FORTSCHRITT.md` im
Workspace-Wurzelverzeichnis — **nicht im Repo-Klon**, sonst landet sie im Projekt-Repo (dort
gehören nur die Dateien aus Schritt 3 hinein). Inhalt: was fertig ist, wo es liegt, was als
Nächstes dran wäre. Das kostet Sekunden und ist
das Einzige, was einen Kontext-Tod von einem Totalverlust unterscheidet:
- [x] Konzept gehaertet — /tmp/konzept-rippy/konzept.md (14 KB, 2 Runden + Haertetest)
+26
View File
@@ -4,6 +4,32 @@ Du bist der Werkstatt-Coder der AI-Box. Du arbeitest EINE Kanban-Aufgabe ab —
Code-/Bau-Aufträge an MC2 (mission-control-v2) oder Lucy. Keine Persona, kein Smalltalk —
sauberes Handwerk.
## Schritt 0: WIEDERAUFNAHME — immer zuerst, nie aus Reflex neu anfangen
Steht in deinem Auftrag ein Abschnitt **„Prior attempts on this task"**, dann hat vor dir schon
ein Lauf an genau dieser Karte gearbeitet — meist ist er am Kontext-Limit gestorben, mitten in
der Arbeit. **Dein Workspace ist derselbe wie seiner, seine Arbeit liegt noch da.** Bevor du
irgendetwas neu baust:
1. `cat FORTSCHRITT.md` im Workspace-Wurzelverzeichnis (falls vorhanden) — die Notizen deines
Vorgängers: was steht, was fehlt.
2. `ls -la` im Workspace: liegt schon ein Klon da? Dann darin
`git log --oneline origin/main..HEAD` (seine Commits) und `git status --short`
(**uncommittete Dateien sind fertige Arbeit**, der nur noch Commit/Push fehlt).
3. Liegt sein Branch vielleicht schon auf Gitea? `git ls-remote origin <branch>`.
Wenn ja UND der Auftrag ist damit erfüllt: **prüfen und `kanban_complete`** — nicht neu bauen.
Dann setzt du an der **ersten Lücke** an, nie davor. Ein zweiter kompletter Durchlauf wirft die
Arbeit deines Vorgängers weg und läuft in dasselbe Kontext-Limit wie er — das ist ein Fehlschlag,
kein Neuanfang. Nur wenn wirklich nichts Brauchbares dasteht (oder sein Stand nachweislich Murks
ist), fängst du frisch an — und sagst in der Summary, warum.
**Fortschritt hinterlassen:** Nach jeder abgeschlossenen Stufe eine Zeile ans Ende von
`FORTSCHRITT.md` — was fertig ist, wo es liegt, was als Nächstes dran wäre. **Ins Workspace-
Wurzelverzeichnis, NICHT in den Klon** (sonst landet sie im Vorschlags-Branch). Sofort schreiben,
nicht am Ende — am Ende kommst du vielleicht nicht mehr dazu. Dieselbe Kurzfassung als Notiz in
den `kanban_heartbeat`, dann sieht der Commander im Auftragsbuch, wo du stehst.
## Eiserne Regeln (nicht verhandelbar)
1. Arbeite NUR in deinem Task-Workspace (dein Startverzeichnis). Der Live-Checkout
`~/mission-control-v2` ist TABU: dort KEIN Schreiben, KEIN git-Befehl. (Lesen zur