Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .empire/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,31 @@ Gemessen: `ritual.sh` gab `64` zurück (kein Brief erzeugt, nichts zugestellt),

**Regel:** In jedem `.cmd`/`.ps1`/`.sh`-Wrapper den Exit-Code der Nutzlast **unmittelbar** sichern (`set "RC=%ERRORLEVEL%"` bzw. `rc=$?`) und am Ende weiterreichen. Kein Kommando zwischen Nutzlast und Sicherung — auch kein Log-`echo`. Vorbild im Haus: `google-mcp/scripts/token-probe-task.cmd`. Und danach die Rot-Probe: der Wrapper muss mit einem garantiert scheiternden Aufruf einen Nicht-Null-Code liefern, sonst ist der Fix unbewiesen.

### Ritual-Heartbeat (buzz#101 — der Leser für diese Exit-Codes)

Ein echter Exit-Code nützt nichts, solange ihn niemand liest. Seit 2026-08-01 hängt hinter jedem Ritual ein Uptime-Kuma-Push-Monitor:

| Ritual | Windows-Aufgabe | Kuma-Monitor | Token in `~/.secrets/master.env` | Intervall |
|---|---|---|---|---|
| Morgenbrief 08:45 | `Buzz-Ritual-Morgenbrief` | `ritual-morgenbrief` (id 64) | `KUMA_PUSH_RITUAL_MORGENBRIEF` | 93 600 s (26 h) |
| Gate-Batch 20:45 | `Buzz-Ritual-Gate-Batch` | `ritual-gate-batch` (id 65) | `KUMA_PUSH_RITUAL_GATE_BATCH` | 93 600 s (26 h) |
| Wochen-Review So 18:00 | `Buzz-Ritual-Wochen-Review` | `ritual-wochen-review` (id 66) | `KUMA_PUSH_RITUAL_WOCHEN_REVIEW` | 691 200 s (8 d) |

- Push: `.empire/tools/ritual-push.sh <mode> <rc>`, aufgerufen von `ritual-task.cmd` **nach** `set "RC=%ERRORLEVEL%"`.
- Abbildung: `rc` 0/1 → `status=up` · `rc` ≥ 2 → **expliziter** `status=down` (Erkennung sofort, nicht erst nach 26 h). Deshalb `maxretries: 0` an den Monitoren — mit Retries würde aus dem Down-Push erst PENDING.
- **Rangfolge im Wrapper:** Ritual-Fehler schlägt Herzschlag-Fehler. Ist das Ritual grün, aber der Push scheitert (Token weg, Kuma tot), meldet die Aufgabe **4** — ein blinder Wächter darf nicht als grün durchgehen. Ein fehlender Token endet nie still mit `exit 0` (das Gegenbeispiel im Haus ist `/opt/agency/push-health.sh`).
- Provisionierung: `agency-infra` `stacks/monitoring/provision/kuma-add-rituals.mjs` (idempotent, Benachrichtigungen zur Laufzeit — s. agency-infra#134).
- **Rot-Probe-Rezept** (Set→Beweis→Revert als ein Block, ohne irgendetwas kaputtzumachen):
```powershell
$env:RITUAL_VAULT_LOG = "C:\nonexistent\vault-log.sh" # Vault-Transport scheitert -> ritual.sh rc=3
cmd /c ".empire\tools\ritual-task.cmd gate-batch" # erwartet: Exit 3, Monitor Down, Alarm
$env:RITUAL_VAULT_LOG = ""
cmd /c ".empire\tools\ritual-task.cmd gate-batch" # erwartet: Exit 0, Monitor Up, Recovery
```
Für den Token-Pfad stattdessen `$env:RITUAL_SECRETS_FILE = "/nonexistent"` — erwartet: `HERZSCHLAG-LÜCKE` in `~/.buzz/ritual.log` und Aufgaben-Exit **4**.
- **Falle:** `HTTP 200` beweist beim Kuma-Push nichts — ein falscher Token liefert `{"ok":false}`. `ritual-push.sh` prüft deshalb den Body, nicht nur den Code.
- **Falle (agency-infra#148):** Ein Push-Monitor **ohne ersten Beat** alarmiert nie. Neue Ritual-Monitore brauchen sofort einen Bootstrap-Beat (`bash ritual-push.sh <mode> 0`), sonst sind sie bis zum ersten echten Lauf wirkungslos still.

### Aus der n8n-Execution-Historie darf man „ist nie gelaufen" NICHT schließen

`GET /executions?workflowId=…` meldete für drei aktive Wochen-Workflows null Executions. Alle drei waren gelaufen. Grund: n8n prunt nach **Anzahl** (Default `EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000`, im Container ist keine `EXECUTIONS_*`-Variable gesetzt), und bei ~2 900 Executions/Tag reicht die Historie nur **3,4 Tage** zurück — kürzer als eine Wochen-Periode.
Expand Down
75 changes: 75 additions & 0 deletions .empire/tools/ritual-push.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# .empire/tools/ritual-push.sh — Herzschlag der drei Führungsrituale (buzz#101)
#
# bash ritual-push.sh <morgenbrief|gate-batch|wochen-review> <rc>
#
# Wird von ritual-task.cmd aufgerufen, NACHDEM der Exit-Code von ritual.sh
# feststeht. Bildet ihn auf den passenden Uptime-Kuma-Push-Monitor ab.
#
# WARUM: Morgenbrief (08:45), Gate-Batch (20:45) und Wochen-Review (So 18:00)
# sind Munirs einziger Kanal auf Backlog, Blocker und Zahlungen. Bis 2026-08-01
# hatten sie keinen einzigen Gesundheits-Monitor — sogar der Gmail-Token hatte
# einen, das tägliche Führungsbriefing nicht. Seit PR #98 liefert die Aufgabe
# überhaupt erst echte Exit-Codes; dieses Script ist der Leser dafür.
#
# Exit-Abbildung (identisch zu ritual-task.cmd, bewusst an EINER Stelle erklärt):
# rc 0 = alle Quellen geliefert -> up
# rc 1 = Brief zugestellt, mit Lücken -> up (Lücken sind der Normalfall;
# würde 1 rot melden, wäre praktisch jeder Tag rot und niemand schaute hin)
# rc >= 2 = Brief hat Munir NICHT erreicht -> down (expliziter Down-Push:
# Erkennung sofort statt erst nach Ablauf des Intervalls)
#
# Eigene Exit-Codes (die Aufgabe wertet sie aus, s. ritual-task.cmd):
# 0 = Push zugestellt · 2 = Aufruffehler · 3 = Push-Token fehlt · 4 = Push abgelehnt
# Ein fehlender Token endet NICHT still mit 0 — ein Herzschlag, der niemanden
# erreicht, ist derselbe Fehler wie gar kein Monitor.
set -u

LOG="$HOME/.buzz/ritual.log"
mkdir -p "$HOME/.buzz" 2>/dev/null || true
log() { printf '%s ritual-push: %s\n' "$(date -Is)" "$1" >> "$LOG"; }

MODE="${1:-}"
RC="${2:-}"
case "$MODE" in
morgenbrief) TOKEN_VAR="KUMA_PUSH_RITUAL_MORGENBRIEF" ;;
gate-batch) TOKEN_VAR="KUMA_PUSH_RITUAL_GATE_BATCH" ;;
wochen-review) TOKEN_VAR="KUMA_PUSH_RITUAL_WOCHEN_REVIEW" ;;
*) log "AUFRUFFEHLER: unbekannter Modus '$MODE' — kein Monitor zugeordnet, kein Herzschlag gesendet"; exit 2 ;;
esac
case "$RC" in
''|*[!0-9]*) log "AUFRUFFEHLER: rc '$RC' ist keine Zahl"; exit 2 ;;
esac

SECRETS="${RITUAL_SECRETS_FILE:-$HOME/.secrets/master.env}"
BASE="${KUMA_PUSH_BASE:-}"
TOKEN="$(eval printf '%s' "\${$TOKEN_VAR:-}")"

# Env schlägt Datei; die Datei wird nur gelesen, wenn nötig (und nie geloggt).
if [ -z "$TOKEN" ] || [ -z "$BASE" ]; then
if [ -r "$SECRETS" ]; then
[ -z "$TOKEN" ] && TOKEN="$(grep -m1 "^${TOKEN_VAR}=" "$SECRETS" | cut -d= -f2- | tr -d '\r"' )"
[ -z "$BASE" ] && BASE="$(grep -m1 '^KUMA_PUSH_BASE=' "$SECRETS" | cut -d= -f2- | tr -d '\r"' )"
else
log "LÜCKE: $SECRETS nicht lesbar"
fi
fi
BASE="${BASE:-https://status.adas.jetzt/api/push}"

if [ -z "$TOKEN" ]; then
log "HERZSCHLAG-LÜCKE: $TOKEN_VAR weder im Env noch in $SECRETS — Monitor '$MODE' bleibt ohne Beat (Ritual-rc war $RC)"
exit 3
fi

if [ "$RC" -le 1 ]; then STATUS="up"; else STATUS="down"; fi

RESP="$(curl -sS -m 20 -w '\n%{http_code}' "$BASE/$TOKEN?status=$STATUS&msg=$MODE-rc$RC" 2>&1)"
CODE="$(printf '%s' "$RESP" | tail -n1)"
BODY="$(printf '%s' "$RESP" | sed '$d')"

# HTTP 200 allein beweist nichts — Kuma antwortet mit {"ok":true|false}.
case "$CODE$BODY" in
200*'"ok":true'*) log "$MODE rc=$RC -> Kuma $STATUS (HTTP $CODE)"; exit 0 ;;
esac
log "PUSH ABGELEHNT: $MODE rc=$RC status=$STATUS -> HTTP ${CODE:-?} ${BODY:-<leer>}"
exit 4
18 changes: 15 additions & 3 deletions .empire/tools/ritual-task.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,24 @@ set "HERE=%~dp0"
"%GITBASH%" -lc "mkdir -p ~/.buzz; echo \"=== $(date -Is) ritual %~1 ===\" >> ~/.buzz/ritual.log; bash '%HERE:\=/%ritual.sh' %~1 --post --telegram --vault >> ~/.buzz/ritual.log 2>&1; rc=$?; echo \"exit=$rc\" >> ~/.buzz/ritual.log; exit $rc"
set "RC=%ERRORLEVEL%"

REM Herzschlag an Uptime Kuma (buzz#101) — MUSS nach dem Sichern von RC stehen,
REM sonst ueberschreibt der Push den zu meldenden Exit-Code. Der Push bekommt RC
REM uebergeben und bildet ihn ab; er ueberschreibt ihn nie: ein gescheitertes
REM Ritual bleibt rot, auch wenn der Push gelingt. Umgekehrt darf ein
REM gescheiterter Push nicht still bleiben — ein Monitor ohne Beat ist derselbe
REM blinde Fleck, den dieses Ticket schliesst.
"%GITBASH%" -lc "bash '%HERE:\=/%ritual-push.sh' %~1 %RC%"
set "PUSHRC=%ERRORLEVEL%"

REM ritual.sh: 0 = alle Quellen geliefert · 1 = Brief zugestellt, mit benannten
REM Luecken · 2 = kein Brief · 3 = Transport gescheitert · 64 = Usage.
REM 0 und 1 heissen beide "der Brief hat Munir erreicht" -> gruen. Alles ab 2
REM heisst "er hat ihn NICHT erreicht" -> muss rot sein. Wuerde auch 1 rot
REM melden, waere die Aufgabe an praktisch jedem Tag rot (Luecken sind der
REM Normalfall) und niemand schaute mehr hin.
if "%RC%"=="0" exit /b 0
if "%RC%"=="1" exit /b 0
exit /b %RC%
REM Rangfolge: Ritual-Fehler schlaegt Herzschlag-Fehler. Ist das Ritual gruen,
REM aber der Herzschlag kaputt, meldet die Aufgabe 4 — sonst wuesste niemand,
REM dass der Waechter selbst blind ist.
if not "%RC%"=="0" if not "%RC%"=="1" exit /b %RC%
if not "%PUSHRC%"=="0" exit /b 4
exit /b 0
Loading