feat: scripts/smoke_test.sh + AGENTS.md R4 verankert

Ein Aufruf startet den Server temporaer auf eigenem Port, prueft alle
bekannten Endpunkte und raeumt sich selbst auf. Agenten muessen nichts
ueber Hintergrund-Jobs, nohup oder Port-Cleanup wissen.

- scripts/smoke_test.sh: trap-basierter Cleanup, setsid-unabhaengig
  via prozessgruppen-fremdem pkill-Fallback, eindeutiger Marker-Name
  in sys.argv[0], 20x100ms Wartezeit aufs Port-Binding.
- AGENTS.md R4: verweist statt auf manuelle curl-Aufrufe auf
  ./scripts/smoke_test.sh; TL;DR und Einstiegs-Block aktualisiert.

Verifiziert: exit 0, Port nach Durchlauf frei (kein Leak).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael 2026-04-24 16:46:13 +02:00
parent 7b471abbf0
commit 3f35cff338
2 changed files with 84 additions and 3 deletions

View file

@ -8,7 +8,7 @@ Diese Datei richtet sich an **Coding-Agenten (Claude, Codex u.ä.), die in diese
1. Erst lesen (Zeilen der Zielstelle nennen), dann ändern.
2. Erst ausführen, dann berichten. Prosa ohne Tool-Call ≠ Ausführung.
3. UI-/Server-Änderung → Server starten + `curl` → Ergebnis zitieren.
3. UI-/Server-Änderung → `./scripts/smoke_test.sh` → Ausgabe zitieren.
4. Nach Refactor: `grep -c <name>` = 1. Sonst nicht fertig.
5. Doku beschreibt Code, nicht die Arbeit am Code.
@ -41,12 +41,16 @@ Für jede angekündigte Änderung muss **mindestens eines** dieser Artefakte vor
Fehlen diese Belege, ist die Aufgabe nicht erledigt — die Tool-Aufrufe absetzen und erneut prüfen.
### R4 UI-/Server-Änderungen gegen das laufende System prüfen
Bei Änderungen an `web/serve.py` oder `web/index.html`: Server starten, betroffene Endpunkte per `curl` testen, und das Ergebnis im Bericht **zitieren**. Beispiel:
Bei Änderungen an `web/serve.py` oder `web/index.html`: führe den Smoke-Test aus und zitiere die Ausgabe im Bericht:
```bash
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8081/templates.json
./scripts/smoke_test.sh
```
Das Skript startet den Server temporär auf einem eigenen Port (Default 8082), prüft alle bekannten Endpunkte und räumt sich selbst auf. Du musst nichts über Hintergrund-Jobs, `&`, `nohup` oder Port-Cleanup wissen. Exit-Code 0 = alle 200; sonst 1.
Für Änderungen, die der Smoke-Test nicht abdeckt (neuer Endpunkt, geänderte Response, JSON-Edit-Flow im Browser), zusätzlich gezielten `curl`-Aufruf oder Browser-Check ergänzen.
„Sieht korrekt aus" ohne ausgeführten Test zählt nicht.
### R5 Nichts in die Doku schreiben, was nicht existiert
@ -66,6 +70,7 @@ Ein Commit = eine logische Änderung. Commit-Message im Stil der bestehenden His
```bash
python3 web/serve.py # startet Server auf http://localhost:8081
./scripts/smoke_test.sh # temporärer Server + Endpunkt-Check + Cleanup (fuer R4)
./scripts/cleanup_server.sh # beendet hängende Instanzen
python3 scripts/validate.py # validiert Template-Struktur
```

76
scripts/smoke_test.sh Executable file
View file

@ -0,0 +1,76 @@
#!/bin/bash
# Startet web/serve.py temporaer, testet die wichtigsten Endpunkte,
# raeumt den Prozess auch bei Abbruch auf. Ein einziger Aufruf; der
# Agent muss nichts ueber Hintergrund-Jobs wissen.
#
# Nutzung: ./scripts/smoke_test.sh # Port 8082
# ./scripts/smoke_test.sh 9000 # anderer Port
# Exit-Code: 0 = alle Endpunkte 200, sonst 1.
set -u
PORT="${1:-8082}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
LOG="/tmp/smoke.$PORT.log"
EXIT_CODE=1
MARKER="SMOKE_TEST_SERVER_$PORT"
# Vorherige Instanzen dieses Smoke-Tests beenden
pkill -f "$MARKER" 2>/dev/null || true
sleep 0.1
# Server im Hintergrund starten (exec → $! ist der Python-Prozess)
cd "$ROOT"
python3 -c "
import sys; sys.argv[0] = '$MARKER'
sys.path.insert(0, 'web')
import http.server, socketserver
from serve import Handler
port = $PORT
print(f'Serving on http://localhost:{port}', flush=True)
with socketserver.TCPServer(('', port), Handler) as httpd:
httpd.serve_forever()
" > "$LOG" 2>&1 &
PID=$!
cleanup() {
kill "$PID" 2>/dev/null || true
wait "$PID" 2>/dev/null || true
# Defensiv: falls der Kill-Signal den Python-Prozess nicht trifft
pkill -f "$MARKER" 2>/dev/null || true
exit "$EXIT_CODE"
}
trap cleanup EXIT INT TERM
# Auf Port-Binding warten (max. 2s)
for i in $(seq 1 20); do
if curl -sf -o /dev/null "http://localhost:$PORT/"; then break; fi
sleep 0.1
done
# Wenn nicht erreichbar: Log ausgeben und fail
if ! curl -sf -o /dev/null "http://localhost:$PORT/"; then
echo "FAIL: Server nicht erreichbar auf Port $PORT"
echo "--- $LOG ---"
cat "$LOG"
EXIT_CODE=1
exit 1
fi
# Endpunkte testen
FAIL=0
for p in "/" "/index.html" "/templates.json" \
"/templates/system/commit_analysis.json" \
"/templates/system/code_reviewer.json" \
"/templates/system/summarizer.json" \
"/templates/user/email_draft.md" \
"/templates/user/brainstorming.md"; do
code=$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:$PORT$p")
status="ok"
[ "$code" = "200" ] || { status="FAIL"; FAIL=1; }
printf '%-50s %s %s\n' "$p" "$code" "$status"
done
EXIT_CODE=$FAIL
if [ "$FAIL" -eq 0 ]; then
echo "--- alle $( (echo "/" "/index.html" "/templates.json" "/templates/system/commit_analysis.json" "/templates/system/code_reviewer.json" "/templates/system/summarizer.json" "/templates/user/email_draft.md" "/templates/user/brainstorming.md") | wc -w ) Endpunkte OK ---"
fi
exit $FAIL