Annahme-Selbstheilung: Orphan-Branches entlarven, veraltete Branches auto-rebasen
Anlass: feature/cleanse-skill-index — ein Werkstatt-Worker hatte git init statt
Klonen gemacht (Orphan-Commit ohne gemeinsamen Vorfahren, Inhalt: ~/.hermes-Index-
Dateien statt Repo-Dateien). Solche Karten sahen aus wie normale Vorschlaege,
liefen bei Annahme aber IMMER in 'refusing to merge unrelated histories' — und
die Fehlermeldung ('bitte am PC aufloesen') war eine Sackgasse. Das passiert
oefter; darum drei Schichten dagegen:
1) ERKENNEN (Auftragsbuch): neue Karten-Flags 'verwaist' (kein merge-base mit
main -> rote Markierung 'kein gemeinsamer Ursprung', Annehmen-Knopf fehlt,
API+Runner halten zusaetzlich dicht) und 'leer' (Diff gegen main leer ->
'bringt nichts'-Badge). Empfehlung auf der Karte: ablehnen mit Grund,
Idee frisch in die Queue.
2) HEILEN (beide Runner, mc2 + lucy): kollidiert der Merge, weil main weiter-
gelaufen ist, versucht der Runner automatisch einen Rebase des Branches auf
main (isolierter Worktree; Gates laufen danach normal, Merge-Message sagt
'auto-rebased'). Nur wenn auch der Rebase kollidiert, faellt die Karte durch —
mit ehrlicher Meldung statt 'am PC aufloesen'.
3) VERHINDERN (werkstatt-SOUL): voll klonen (nie git init/--depth), Selbstcheck
'git merge-base HEAD origin/main' + fetch/rebase vor JEDEM Push, nie
~/.hermes-Artefakte committen.
Doku: AUFTRAGSBUCH.md + FALLEN.md (Erkennungsmuster: Diff 0 Dateien + behind ~
ganze Historie) + OFFENE-FAEDEN. Geprueft: py_compile gruen, bash -n beide
Runner gruen, tsc+vite build gruen (dist dabei); merge-base-Verhalten am echten
kaputten Branch auf der Box verifiziert.
This commit is contained in:
@@ -141,6 +141,10 @@ def _repo_items(repo: str, statuses: dict, gutachten: dict) -> list[dict]:
|
|||||||
if ahead == 0 and ((status or {}).get("state") not in ("laeuft", "rollback")):
|
if ahead == 0 and ((status or {}).get("state") not in ("laeuft", "rollback")):
|
||||||
continue # bereits in main enthalten → keine offene Entscheidung mehr
|
continue # bereits in main enthalten → keine offene Entscheidung mehr
|
||||||
behind = int((_git(repo, ["rev-list", "--count", f"{ref}..origin/main"]).stdout or "0").strip() or 0)
|
behind = int((_git(repo, ["rev-list", "--count", f"{ref}..origin/main"]).stdout or "0").strip() or 0)
|
||||||
|
# Kaputt aufgesetzte Branches entlarven (Worker machte git init/Shallow statt zu
|
||||||
|
# klonen): ohne gemeinsamen Vorfahren kann git NIE mergen — Annehmen wäre ein
|
||||||
|
# garantierter Fehllauf („refusing to merge unrelated histories").
|
||||||
|
verwaist = _git(repo, ["merge-base", "origin/main", ref]).returncode != 0
|
||||||
show = _git(repo, ["show", "-s", "--format=%s%x1f%b%x1f%ct%x1f%an", ref])
|
show = _git(repo, ["show", "-s", "--format=%s%x1f%b%x1f%ct%x1f%an", ref])
|
||||||
subject, body, cts, author = ((show.stdout or "").split("\x1f") + ["", "", "", ""])[:4]
|
subject, body, cts, author = ((show.stdout or "").split("\x1f") + ["", "", "", ""])[:4]
|
||||||
ts_val = int(cts) if cts.strip().isdigit() else None
|
ts_val = int(cts) if cts.strip().isdigit() else None
|
||||||
@@ -170,6 +174,11 @@ def _repo_items(repo: str, statuses: dict, gutachten: dict) -> list[dict]:
|
|||||||
"empfehlung": stempel,
|
"empfehlung": stempel,
|
||||||
"ahead": ahead,
|
"ahead": ahead,
|
||||||
"behind": behind,
|
"behind": behind,
|
||||||
|
"verwaist": verwaist,
|
||||||
|
# Diff gegen main ist leer → der Branch brächte nichts (Inhalt schon in main
|
||||||
|
# oder Worker hat am Repo vorbei gearbeitet). Bei verwaist ist der Diff
|
||||||
|
# technisch leer (kein merge-base) — dann zählt nur das verwaist-Flag.
|
||||||
|
"leer": not verwaist and ahead > 0 and not files_raw,
|
||||||
"shortstat": stat,
|
"shortstat": stat,
|
||||||
"files": files,
|
"files": files,
|
||||||
"files_truncated": len(files_raw) > 60,
|
"files_truncated": len(files_raw) > 60,
|
||||||
@@ -227,6 +236,12 @@ def accept(branch: str, repo: str = "mc2") -> dict:
|
|||||||
state = (_statuses().get(key) or {}).get("state")
|
state = (_statuses().get(key) or {}).get("state")
|
||||||
if state in ("laeuft", "rollback"):
|
if state in ("laeuft", "rollback"):
|
||||||
return {"ok": False, "error": "Für diesen Vorschlag läuft bereits ein Annahme-Lauf."}
|
return {"ok": False, "error": "Für diesen Vorschlag läuft bereits ein Annahme-Lauf."}
|
||||||
|
# Kaputt aufgesetzter Branch (kein gemeinsamer Vorfahre) → Merge kann NIE gelingen;
|
||||||
|
# gar nicht erst einen Runner starten (die UI blendet den Knopf aus, die API hält dicht).
|
||||||
|
if _git(repo, ["merge-base", "origin/main", f"origin/{branch}"]).returncode != 0:
|
||||||
|
return {"ok": False, "error": "Dieser Branch hat keinen gemeinsamen Ursprung mit main "
|
||||||
|
"(kaputt aufgesetzt, z. B. git init statt Klonen) — Annehmen ist technisch unmöglich. "
|
||||||
|
"Bitte ablehnen (gern mit Grund) und die Idee neu in die Queue geben."}
|
||||||
|
|
||||||
# Runner als /tmp-Kopie starten: deploy.sh resettet das Repo hart — das Original-Skript
|
# Runner als /tmp-Kopie starten: deploy.sh resettet das Repo hart — das Original-Skript
|
||||||
# würde einem laufenden bash unter den Füßen getauscht (bekannte Selbst-Reset-Falle).
|
# würde einem laufenden bash unter den Füßen getauscht (bekannte Selbst-Reset-Falle).
|
||||||
|
|||||||
@@ -57,13 +57,36 @@ git rev-parse --verify -q "refs/remotes/origin/$BRANCH" >/dev/null \
|
|||||||
|
|
||||||
PRE="$(git rev-parse origin/main)"
|
PRE="$(git rev-parse origin/main)"
|
||||||
|
|
||||||
|
# Kaputt aufgesetzte Branches (Worker machte git init/Shallow statt zu klonen) haben KEINEN
|
||||||
|
# gemeinsamen Vorfahren — git verweigert den Merge immer. Ehrlich sagen statt „Konflikt".
|
||||||
|
git merge-base origin/main "origin/$BRANCH" >/dev/null 2>&1 \
|
||||||
|
|| fail "Branch hat keinen gemeinsamen Ursprung mit main (kaputt aufgesetzt, z. B. git init statt Klonen) — bitte ablehnen (mit Grund) und die Idee neu in die Queue geben"
|
||||||
|
|
||||||
# Isolierter Worktree — der Live-Checkout bleibt bis zum Deploy unberührt.
|
# Isolierter Worktree — der Live-Checkout bleibt bis zum Deploy unberührt.
|
||||||
cleanup_wt
|
cleanup_wt
|
||||||
git worktree add --detach "$WT" origin/main >/dev/null 2>&1 || fail "Worktree konnte nicht angelegt werden"
|
git worktree add --detach "$WT" origin/main >/dev/null 2>&1 || fail "Worktree konnte nicht angelegt werden"
|
||||||
|
MERGE_MSG="Auftragsbuch: '$BRANCH' angenommen (Ein-Klick-Gate)"
|
||||||
if ! git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
if ! git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
||||||
merge --no-ff "origin/$BRANCH" -m "Auftragsbuch: '$BRANCH' angenommen (Ein-Klick-Gate)" >>"$LOG" 2>&1; then
|
merge --no-ff "origin/$BRANCH" -m "$MERGE_MSG" >>"$LOG" 2>&1; then
|
||||||
git -C "$WT" merge --abort 2>/dev/null || true
|
git -C "$WT" merge --abort 2>/dev/null || true
|
||||||
fail "Merge-Konflikt mit main — der Branch ist veraltet, bitte am PC auflösen"
|
# Selbstheilung: veralteten Branch mechanisch auf main rebasen (zweiter Worktree am
|
||||||
|
# Branch-Kopf). Klappt das sauber, wird der rebasede Stand gemergt — kein PC nötig.
|
||||||
|
status "laeuft" "Merge-Konflikt — Auto-Rebase wird versucht"
|
||||||
|
WT2="/tmp/annahme-rebase-$SLUG"
|
||||||
|
git worktree remove --force "$WT2" 2>/dev/null || true
|
||||||
|
REBASED=""
|
||||||
|
if git worktree add --detach "$WT2" "origin/$BRANCH" >/dev/null 2>&1 \
|
||||||
|
&& git -C "$WT2" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
||||||
|
rebase origin/main >>"$LOG" 2>&1; then
|
||||||
|
REBASED="$(git -C "$WT2" rev-parse HEAD)"
|
||||||
|
else
|
||||||
|
git -C "$WT2" rebase --abort 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
git worktree remove --force "$WT2" 2>/dev/null || true
|
||||||
|
[ -n "$REBASED" ] || fail "Merge-Konflikt mit main, Auto-Rebase scheiterte ebenfalls — echter Inhaltskonflikt; am einfachsten ablehnen und die Idee neu in die Queue geben (frischer Branch von aktuellem main)"
|
||||||
|
git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
||||||
|
merge --no-ff "$REBASED" -m "$MERGE_MSG — auto-rebased (Branch war veraltet)" >>"$LOG" 2>&1 \
|
||||||
|
|| { git -C "$WT" merge --abort 2>/dev/null || true; fail "Merge nach Auto-Rebase fehlgeschlagen (unerwartet) — Log: $LOG"; }
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# py_compile-Gate über die durch den Merge geänderten Python-Dateien (AGENTS.md-Regel).
|
# py_compile-Gate über die durch den Merge geänderten Python-Dateien (AGENTS.md-Regel).
|
||||||
|
|||||||
+23
-2
@@ -130,12 +130,33 @@ git -C "$LUCY" fetch -q origin || fail "git fetch (Gitea) fehlgeschlagen"
|
|||||||
git -C "$LUCY" rev-parse --verify -q "refs/remotes/origin/$BRANCH" >/dev/null \
|
git -C "$LUCY" rev-parse --verify -q "refs/remotes/origin/$BRANCH" >/dev/null \
|
||||||
|| fail "Branch origin/$BRANCH existiert nicht (schon gemergt/gelöscht?)"
|
|| fail "Branch origin/$BRANCH existiert nicht (schon gemergt/gelöscht?)"
|
||||||
|
|
||||||
|
# Kaputt aufgesetzte Branches (kein gemeinsamer Vorfahre) → Merge kann NIE gelingen.
|
||||||
|
git -C "$LUCY" merge-base origin/main "origin/$BRANCH" >/dev/null 2>&1 \
|
||||||
|
|| fail "Branch hat keinen gemeinsamen Ursprung mit main (kaputt aufgesetzt, z. B. git init statt Klonen) — bitte ablehnen (mit Grund) und die Idee neu in die Queue geben"
|
||||||
|
|
||||||
cleanup_wt
|
cleanup_wt
|
||||||
git -C "$LUCY" worktree add --detach "$WT" origin/main >/dev/null 2>&1 || fail "Worktree konnte nicht angelegt werden"
|
git -C "$LUCY" worktree add --detach "$WT" origin/main >/dev/null 2>&1 || fail "Worktree konnte nicht angelegt werden"
|
||||||
|
MERGE_MSG="Auftragsbuch: Lucy-Vorschlag '$BRANCH' angenommen (Ein-Klick-Gate)"
|
||||||
if ! git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
if ! git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
||||||
merge --no-ff "origin/$BRANCH" -m "Auftragsbuch: Lucy-Vorschlag '$BRANCH' angenommen (Ein-Klick-Gate)" >>"$LOG" 2>&1; then
|
merge --no-ff "origin/$BRANCH" -m "$MERGE_MSG" >>"$LOG" 2>&1; then
|
||||||
git -C "$WT" merge --abort 2>/dev/null || true
|
git -C "$WT" merge --abort 2>/dev/null || true
|
||||||
fail "Merge-Konflikt mit main — der Branch ist veraltet, bitte am PC auflösen"
|
# Selbstheilung: veralteten Branch mechanisch auf main rebasen (wie im MC2-Runner).
|
||||||
|
status "laeuft" "Merge-Konflikt — Auto-Rebase wird versucht"
|
||||||
|
WT2="/tmp/annahme-rebase-$SLUG"
|
||||||
|
git -C "$LUCY" worktree remove --force "$WT2" 2>/dev/null || true
|
||||||
|
REBASED=""
|
||||||
|
if git -C "$LUCY" worktree add --detach "$WT2" "origin/$BRANCH" >/dev/null 2>&1 \
|
||||||
|
&& git -C "$WT2" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
||||||
|
rebase origin/main >>"$LOG" 2>&1; then
|
||||||
|
REBASED="$(git -C "$WT2" rev-parse HEAD)"
|
||||||
|
else
|
||||||
|
git -C "$WT2" rebase --abort 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
git -C "$LUCY" worktree remove --force "$WT2" 2>/dev/null || true
|
||||||
|
[ -n "$REBASED" ] || fail "Merge-Konflikt mit main, Auto-Rebase scheiterte ebenfalls — echter Inhaltskonflikt; am einfachsten ablehnen und die Idee neu in die Queue geben (frischer Branch von aktuellem main)"
|
||||||
|
git -C "$WT" -c user.name="Auftragsbuch" -c user.email="auftragsbuch@box.local" \
|
||||||
|
merge --no-ff "$REBASED" -m "$MERGE_MSG — auto-rebased (Branch war veraltet)" >>"$LOG" 2>&1 \
|
||||||
|
|| { git -C "$WT" merge --abort 2>/dev/null || true; fail "Merge nach Auto-Rebase fehlgeschlagen (unerwartet) — Log: $LOG"; }
|
||||||
fi
|
fi
|
||||||
|
|
||||||
status "laeuft" "Push nach main läuft"
|
status "laeuft" "Push nach main läuft"
|
||||||
|
|||||||
@@ -11,10 +11,19 @@ sauberes Handwerk.
|
|||||||
2. Ergebnis eines Code-Auftrags ist IMMER ein Vorschlags-Branch auf Gitea — NIEMALS Push
|
2. Ergebnis eines Code-Auftrags ist IMMER ein Vorschlags-Branch auf Gitea — NIEMALS Push
|
||||||
auf main, NIEMALS mergen, NIEMALS deployen, NIEMALS Dienste neu starten. Der Commander
|
auf main, NIEMALS mergen, NIEMALS deployen, NIEMALS Dienste neu starten. Der Commander
|
||||||
klickt die Karte im Auftragsbuch.
|
klickt die Karte im Auftragsbuch.
|
||||||
3. Frisch klonen statt Live-Checkout nutzen:
|
3. Frisch und VOLL klonen statt Live-Checkout nutzen:
|
||||||
`git clone https://git.tobisniceshomelab.ddnsfree.com/Hitonabi/mission-control-v2`
|
`git clone https://git.tobisniceshomelab.ddnsfree.com/Hitonabi/mission-control-v2`
|
||||||
(Credentials liegen in `~/.git-credentials`; Lucy-Repo: `.../Hitonabi/lucy`).
|
(Credentials liegen in `~/.git-credentials`; Lucy-Repo: `.../Hitonabi/lucy`).
|
||||||
|
NIEMALS `git init`, NIEMALS `--depth`/Shallow, NIEMALS in einem Verzeichnis committen,
|
||||||
|
das nicht dieser frische Klon ist — sonst entsteht ein Branch OHNE gemeinsamen
|
||||||
|
Ursprung, den das Auftragsbuch als „kaputt aufgesetzt" aussortiert (Vorfall
|
||||||
|
12.07.2026: feature/cleanse-skill-index war ein git-init-Orphan mit ~/.hermes-Dateien).
|
||||||
Branch-Namen: `wartung/<kurz>`, `feature/<kurz>` oder `doku/<kurz>`.
|
Branch-Namen: `wartung/<kurz>`, `feature/<kurz>` oder `doku/<kurz>`.
|
||||||
|
SELBSTCHECK vor dem Push (Pflicht, beide Zeilen müssen klappen):
|
||||||
|
`git merge-base HEAD origin/main` (muss einen Hash liefern) und
|
||||||
|
`git fetch origin && git rebase origin/main` (veraltete Basis sofort begradigen;
|
||||||
|
Konflikt → `kanban_block`, nicht raten). Committe NUR Dateien, die zum Repo gehören —
|
||||||
|
`~/.hermes`-Artefakte (.usage.json, .bundled_manifest, Skill-Indizes) gehören NIE hinein.
|
||||||
4. Gate vor dem Push: `python3 -m py_compile` für JEDE geänderte .py-Datei. Frontend
|
4. Gate vor dem Push: `python3 -m py_compile` für JEDE geänderte .py-Datei. Frontend
|
||||||
(`frontend/`) nur anfassen, wenn der Auftrag es verlangt — die Box kann kein
|
(`frontend/`) nur anfassen, wenn der Auftrag es verlangt — die Box kann kein
|
||||||
`npm build`; das ehrlich in Commit-Text und Summary sagen.
|
`npm build`; das ehrlich in Commit-Text und Summary sagen.
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ bewiesen; ein Eigenbau hätte all das nur nachgebaut.
|
|||||||
## Was „Annehmen" bei einem Patch macht (deploy/auftrag-annehmen.sh)
|
## Was „Annehmen" bei einem Patch macht (deploy/auftrag-annehmen.sh)
|
||||||
|
|
||||||
1. Merge des Branches in einem **isolierten Worktree** (Live-Checkout bleibt unberührt).
|
1. Merge des Branches in einem **isolierten Worktree** (Live-Checkout bleibt unberührt).
|
||||||
|
Kollidiert der Merge, weil main weitergelaufen ist, versucht der Runner **automatisch
|
||||||
|
einen Rebase** des Branches auf main (Selbstheilung für veraltete Vorschläge) — erst
|
||||||
|
wenn auch der kollidiert, fällt die Karte mit ehrlicher Meldung durch.
|
||||||
2. `py_compile`-Gate über die geänderten Python-Dateien.
|
2. `py_compile`-Gate über die geänderten Python-Dateien.
|
||||||
3. Push nach `main` auf Gitea (mit Retry).
|
3. Push nach `main` auf Gitea (mit Retry).
|
||||||
4. Deploy (als /tmp-Kopie von deploy.sh — Selbst-Reset-Falle) — die Zentrale
|
4. Deploy (als /tmp-Kopie von deploy.sh — Selbst-Reset-Falle) — die Zentrale
|
||||||
@@ -64,6 +67,15 @@ Der Lauf ist eine eigene systemd-Unit (detached) — er überlebt den Neustart d
|
|||||||
Backends, das ihn gestartet hat. Fortschritt steht live auf der Karte
|
Backends, das ihn gestartet hat. Fortschritt steht live auf der Karte
|
||||||
(`/srv/models/mc2-auftragsbuch.json`).
|
(`/srv/models/mc2-auftragsbuch.json`).
|
||||||
|
|
||||||
|
**Kaputt aufgesetzte Branches** (Worker machte `git init`/Shallow statt zu klonen → kein
|
||||||
|
gemeinsamer Ursprung mit main, „refusing to merge unrelated histories") erkennt das
|
||||||
|
Auftragsbuch an der Quelle: rote Markierung „kein gemeinsamer Ursprung", der
|
||||||
|
Annehmen-Knopf fehlt (Annehmen wäre ein garantierter Fehllauf), API und Runner halten
|
||||||
|
zusätzlich dicht. Ebenso markiert: „Diff leer — bringt nichts" (Branch würde gegenüber
|
||||||
|
main nichts ändern). In beiden Fällen: **ablehnen mit Grund** und die Idee frisch in die
|
||||||
|
Queue geben; die Prävention (voll klonen, merge-base-Selbstcheck, fetch+rebase vor dem
|
||||||
|
Push) steht in der werkstatt-SOUL.
|
||||||
|
|
||||||
## Was „Annehmen" bei einer LUCY-Karte macht (deploy/lucy-annahme.sh)
|
## Was „Annehmen" bei einer LUCY-Karte macht (deploy/lucy-annahme.sh)
|
||||||
|
|
||||||
Lucy (Electron) lebt auf dem Windows-PC; ihr `dist` liegt nicht im Repo — die Box
|
Lucy (Electron) lebt auf dem Windows-PC; ihr `dist` liegt nicht im Repo — die Box
|
||||||
|
|||||||
@@ -26,6 +26,17 @@ Neue Fallen: hier eintragen, mit Datum und Symptom._
|
|||||||
CR-Falle (`sed 's/\r$//'`).
|
CR-Falle (`sed 's/\r$//'`).
|
||||||
- **Stale `index.lock`** im Box-Repo nach Deploy-Abbruch: Alter prüfen, dann löschen.
|
- **Stale `index.lock`** im Box-Repo nach Deploy-Abbruch: Alter prüfen, dann löschen.
|
||||||
- **`hermes` ist über SSH nicht im PATH** → immer `bash -lc 'hermes …'`.
|
- **`hermes` ist über SSH nicht im PATH** → immer `bash -lc 'hermes …'`.
|
||||||
|
- **Werkstatt-Orphan-Branches („refusing to merge unrelated histories"):** macht ein
|
||||||
|
Worker `git init`/Shallow statt voll zu klonen, entsteht ein Branch OHNE gemeinsamen
|
||||||
|
Vorfahren — Erkennungsmuster auf der Karte: **Diff „0 Dateien" + „hinter main" ≈ ganze
|
||||||
|
Historie** (z. B. 386). Merge ist NIE möglich; oft ist der Inhalt obendrein Müll
|
||||||
|
(~/.hermes-Dateien statt Repo-Dateien). Seit 12.07.2026 markiert das Auftragsbuch solche
|
||||||
|
Karten („kein gemeinsamer Ursprung", Annehmen-Knopf weg) → ablehnen mit Grund, Idee neu
|
||||||
|
in die Queue. Prävention steht in der werkstatt-SOUL (voll klonen + merge-base-Selbstcheck).
|
||||||
|
- **Ehrlich-veraltete Branches (echter Merge-Konflikt):** die Annahme versucht seit
|
||||||
|
12.07.2026 automatisch einen Rebase auf main (isolierter Worktree, Gates laufen danach
|
||||||
|
normal). Nur wenn AUCH der Rebase kollidiert, fällt die Karte durch — dann ablehnen und
|
||||||
|
die Idee frisch einqueuen statt „am PC auflösen".
|
||||||
|
|
||||||
## Box / systemd / llama-swap
|
## Box / systemd / llama-swap
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,13 @@ keine zweite Liste anlegen. Verdikte werden NICHT als „offen" geführt → [VE
|
|||||||
durch: A4-Turncheck Default AUS (680 Entscheidungen, 79 % der Halte umsonst), dist am PC
|
durch: A4-Turncheck Default AUS (680 Entscheidungen, 79 % der Halte umsonst), dist am PC
|
||||||
gebaut. **Erster Live-Lauf fand 2 Runner-Bugs** (Start-Process-Quoting bei Leerzeichen-Pfad,
|
gebaut. **Erster Live-Lauf fand 2 Runner-Bugs** (Start-Process-Quoting bei Leerzeichen-Pfad,
|
||||||
f-String-`\"` auf Python 3.14 → Poll blind; Abschluss manuell nachgezogen, Build war grün) —
|
f-String-`\"` auf Python 3.14 → Poll blind; Abschluss manuell nachgezogen, Build war grün) —
|
||||||
Fixes + Executor-Fensterblitz-Fix in Karte `wartung/lucy-annahme-fixes`. Details FALLEN.md.
|
Fixes + Executor-Fensterblitz-Fix in Karte `wartung/lucy-annahme-fixes` (✅ angenommen).
|
||||||
**Der nächste Lucy-Auftrag ist der ehrliche Voll-Automatik-Test.**
|
Details FALLEN.md. **Der nächste Lucy-Auftrag ist der ehrliche Voll-Automatik-Test.**
|
||||||
|
- **Annahme-Selbstheilung (12.07. abends, nach cleanse-skill-index-Vorfall):** Auftragsbuch
|
||||||
|
erkennt Orphan-Branches („kein gemeinsamer Ursprung", Annehmen-Knopf weg) und leere
|
||||||
|
Diffs; beide Runner rebasen veraltete Branches automatisch, bevor sie aufgeben;
|
||||||
|
werkstatt-SOUL: voll klonen + merge-base-Selbstcheck + fetch/rebase vor Push, nie
|
||||||
|
~/.hermes-Artefakte committen. Karte `wartung/annahme-selbstheilung`.
|
||||||
- **S4 „leg los zuendung" ✅ gebaut (12.07.):** Idle-Radar (`deploy/idle-radar-feed.sh`,
|
- **S4 „leg los zuendung" ✅ gebaut (12.07.):** Idle-Radar (`deploy/idle-radar-feed.sh`,
|
||||||
Hermes-Cron nächtlich 03:45): Journal-Fehlermuster + Traum-Funde → max. 2 belegte rohe
|
Hermes-Cron nächtlich 03:45): Journal-Fehlermuster + Traum-Funde → max. 2 belegte rohe
|
||||||
Ideen/Nacht ins native Kanban (Ehrlichkeits-Gate prüft Beleg-Zitate mechanisch,
|
Ideen/Nacht ins native Kanban (Ehrlichkeits-Gate prüft Beleg-Zitate mechanisch,
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
+29
-29
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
<link rel="manifest" href="/manifest.webmanifest" />
|
<link rel="manifest" href="/manifest.webmanifest" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<title>Mission Control 2.0</title>
|
<title>Mission Control 2.0</title>
|
||||||
<script type="module" crossorigin src="/assets/index-D-87Dv5s.js"></script>
|
<script type="module" crossorigin src="/assets/index-DyMSyf_4.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-Cq3xDDcK.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-Cq3xDDcK.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -461,6 +461,8 @@ export interface AuftragItem {
|
|||||||
files: { status: string; path: string }[]
|
files: { status: string; path: string }[]
|
||||||
files_truncated: boolean
|
files_truncated: boolean
|
||||||
frontend_ohne_build: boolean // Frontend-Quelltext ohne dist → Box kann nicht bauen
|
frontend_ohne_build: boolean // Frontend-Quelltext ohne dist → Box kann nicht bauen
|
||||||
|
verwaist?: boolean // kein gemeinsamer Ursprung mit main (kaputt aufgesetzt) → Merge unmöglich
|
||||||
|
leer?: boolean // Diff gegen main ist leer → bringt nichts (schon in main / am Repo vorbei)
|
||||||
status: AuftragStatus | null
|
status: AuftragStatus | null
|
||||||
// Empfehlungs-Stempel des nächtlichen Karten-Gutachters (Meinung, kein Gate).
|
// Empfehlungs-Stempel des nächtlichen Karten-Gutachters (Meinung, kein Gate).
|
||||||
empfehlung: { empfehlung: "ANNEHMEN" | "ABLEHNEN" | "UNKLAR"; satz: string; richter: string } | null
|
empfehlung: { empfehlung: "ANNEHMEN" | "ABLEHNEN" | "UNKLAR"; satz: string; richter: string } | null
|
||||||
|
|||||||
@@ -344,6 +344,7 @@ function ProposalCard({
|
|||||||
|
|
||||||
{!running && !decided && (
|
{!running && !decided && (
|
||||||
<div className="flex shrink-0 items-center gap-2">
|
<div className="flex shrink-0 items-center gap-2">
|
||||||
|
{!item.verwaist && (
|
||||||
<button
|
<button
|
||||||
disabled={!!busy[k]}
|
disabled={!!busy[k]}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -355,6 +356,7 @@ function ProposalCard({
|
|||||||
className="flex h-9 items-center gap-1.5 rounded-lg border border-emerald-500/40 bg-emerald-500/10 px-3 text-[11px] font-bold uppercase tracking-wide text-emerald-300 transition-all hover:bg-emerald-500/20 cursor-pointer disabled:opacity-50">
|
className="flex h-9 items-center gap-1.5 rounded-lg border border-emerald-500/40 bg-emerald-500/10 px-3 text-[11px] font-bold uppercase tracking-wide text-emerald-300 transition-all hover:bg-emerald-500/20 cursor-pointer disabled:opacity-50">
|
||||||
{busy[k] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Check className="h-3.5 w-3.5" />} Annehmen
|
{busy[k] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Check className="h-3.5 w-3.5" />} Annehmen
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
disabled={!!busy["ab:" + k]}
|
disabled={!!busy["ab:" + k]}
|
||||||
onClick={() => setRejecting((v) => !v)}
|
onClick={() => setRejecting((v) => !v)}
|
||||||
@@ -401,11 +403,29 @@ function ProposalCard({
|
|||||||
<p className="text-[11px] text-muted-foreground">{item.status.detail}</p>
|
<p className="text-[11px] text-muted-foreground">{item.status.detail}</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{item.verwaist && (
|
||||||
|
<p className="rounded-lg border border-red-500/30 bg-red-500/5 px-2 py-1.5 text-[11px] text-red-300/90">
|
||||||
|
<b>Kaputt aufgesetzt:</b> Dieser Branch hat keinen gemeinsamen Ursprung mit main (der Werkstatt-Worker
|
||||||
|
hat nicht richtig geklont) — Annehmen ist technisch unmöglich, deshalb fehlt der Knopf.
|
||||||
|
Am besten <b>ablehnen mit Grund</b>; die Idee kann danach frisch in die Queue.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground">
|
<div className="flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground">
|
||||||
<span className="rounded bg-background/40 px-1.5 py-0.5 font-mono">{item.ahead} Commit{item.ahead === 1 ? "" : "s"}</span>
|
<span className="rounded bg-background/40 px-1.5 py-0.5 font-mono">{item.ahead} Commit{item.ahead === 1 ? "" : "s"}</span>
|
||||||
{item.shortstat && <span className="rounded bg-background/40 px-1.5 py-0.5 font-mono">{item.shortstat.trim()}</span>}
|
{item.shortstat && <span className="rounded bg-background/40 px-1.5 py-0.5 font-mono">{item.shortstat.trim()}</span>}
|
||||||
{item.behind > 0 && (
|
{item.verwaist && (
|
||||||
<span className="flex items-center gap-1 rounded bg-amber-500/10 px-1.5 py-0.5 text-amber-300" title="main ist seit diesem Vorschlag weitergelaufen">
|
<span className="flex items-center gap-1 rounded bg-red-500/10 px-1.5 py-0.5 text-red-300" title="Kein gemeinsamer Vorfahre mit main — git kann diesen Branch niemals mergen.">
|
||||||
|
<AlertTriangle className="h-3 w-3" /> kein gemeinsamer Ursprung
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{item.leer && (
|
||||||
|
<span className="flex items-center gap-1 rounded bg-amber-500/10 px-1.5 py-0.5 text-amber-300" title="Der Diff gegen main ist leer — der Branch würde nichts verändern (Inhalt schon in main oder am Repo vorbei gearbeitet).">
|
||||||
|
<AlertTriangle className="h-3 w-3" /> Diff leer — bringt nichts
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{item.behind > 0 && !item.verwaist && (
|
||||||
|
<span className="flex items-center gap-1 rounded bg-amber-500/10 px-1.5 py-0.5 text-amber-300" title="main ist seit diesem Vorschlag weitergelaufen — bei Konflikten versucht die Annahme automatisch einen Rebase.">
|
||||||
<AlertTriangle className="h-3 w-3" /> {item.behind} hinter main
|
<AlertTriangle className="h-3 w-3" /> {item.behind} hinter main
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user