Files
werkrevisor/docs/betrieb-git.javagil.de.md
mhoennigandClaude Opus 5.5 5b53d48bca
werkator/server build succeeded after 00:00
werkator build succeeded after 00:06
werkator/werkrevisor-statistics build succeeded after 00:00
docs: classifier stage 1 is implemented; TYPESAFE_API_KEY and [engine] in the operations guides
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:18:47 +02:00

213 lines
15 KiB
Markdown

# Betrieb: KI-Review für git.javagil.de (Versuch mit `mi/werkprobe`)
Stand: 2026-10-05.
Diese Datei beschreibt die laufende Testintegration.
Sie enthält keine Secrets, nur deren Fundorte.
## Überblick
Werkator startet für jeden neuen Head-Commit eines offenen PRs ohne WIP-Präfix einen Review-Build.
Der Build läuft in einer Werkdock-Sandbox mit werkrevisor.
werkrevisor liest den PR über die Gitea-API, wendet feste Regeln an, lässt PR-Agent das Modell fragen und bildet das Urteil.
Danach schreibt werkrevisor einen Kommentar und ein Review in Gitea.
Werkator meldet den Exit-Code als Status `ai-review/gate` an die Head-SHA.
```mermaid
flowchart LR
dev["Entwickler"] -- "push, PR ohne WIP" --> gitea
human["Mensch, z. B. mi"] -- "Approval bei YELLOW" --> gitea
subgraph gitea["Gitea"]
pr["Pull Request"]
bp{"Branch Protection"}
end
subgraph host["mih09"]
werkator["Werkator"]
subgraph sandbox["Werkdock-Sandbox, frisches Home"]
werkrevisor["werkrevisor"] --> pragent["PR-Agent"]
end
mcfg[("Maschinen-Konfiguration:<br/>Build ai-review, Secrets,<br/>WERKREVISOR_CONFIG_TOML")]
end
openrouter["OpenRouter"] --> llm["Sprachmodell"]
werkator -- "pollt neue Heads und offene PRs" --> pr
mcfg -. "Befehl, Umgebung" .-> werkator
werkator -- "CI-Build" --> ci["normaler Build"]
werkator -- "PR-Target-Build" --> werkrevisor
werkrevisor -- "liest PR, Diff, Dateien" --> pr
pragent -- "Prompt" --> openrouter
werkrevisor -- "Kommentar, Approval / Request changes /<br/>Review-Anfrage, ai-review/assessment" --> pr
werkator -- "Status werkator und ai-review/gate" --> pr
pr --> bp
bp -- "Merge erlaubt oder gesperrt" --> dev
```
| Urteil | Gitea-Aktion von werkrevisor | `ai-review/gate` | Merge |
| ------ | ----------------------------------------------------------------- | ---------------- | ---------------------------------------- |
| GREEN | Kommentar, Review `APPROVED` für die Head-SHA | success | möglich, wenn die CI grün ist |
| YELLOW | Kommentar, offizielle Review-Anfrage an `mi` | success | gesperrt bis zu einem Approval von `mi` |
| RED | Kommentar, Review `REQUEST_CHANGES` mit höchstens 3 Befunden | failure | gesperrt bis zu einem neuen Review |
| ERROR | Kommentar „review not completed“, kein Review | failure | gesperrt |
Ein PR mit WIP-Präfix bekommt keinen Review und deshalb keinen `ai-review/gate`-Status; er ist damit gesperrt.
## Versionen
| Komponente | Version |
| ----------- | ---------------------------------------------------------------------------------------- |
| Gitea | 1.27.3 (git.javagil.de) |
| Werkator | 1.36.1 auf mih09 (`trigger.onPullRequestTarget`, PR#117; frisches Home je Review, PR#118) |
| werkrevisor | 0.4.0 (`mi/werkrevisor`), Rootfs `werkrevisor-rootfs-0.4.0.tar.zst`, Konfiguration in `WERKREVISOR_CONFIG_TOML` |
| PR-Agent | 0.47.0, Image `pragent/pr-agent@sha256:7d98954c29289846a08faf00aaea0f1f1375b1676cd8a2ed303e0af07010af7a` |
| Modell | `openrouter/anthropic/claude-sonnet-5.5` |
## Konfiguration ohne Secrets
Die Betreiber-Konfiguration ist `config/werkprobe.toml` im werkrevisor-Image (`/werkrevisor/config/werkprobe.toml`).
Ein PR kann sie nicht ändern.
Wichtige Werte:
- Preise 2,00 / 10,00 USD pro 1 Mio. Input- / Output-Tokens;
- höchstens 25.000 Input- und 4.000 Output-Tokens;
- höchstens 0,20 USD pro Review, einschließlich einer Wiederholung;
- automatisch freigebbar: nur Doku, nur hinzugefügte Tests, Doku plus Tests, Refactoring mit unveränderten Tests;
- immer mindestens YELLOW: Pfade zu Auth, Rechten, Migrationen, Secrets, CI und Deployment (`.werkator*`, `.gitea/**`, `Dockerfile*`, Build-Dateien);
- Secret-Scan der hinzugefügten Zeilen: Ein Treffer führt zu YELLOW, ohne Modellaufruf.
Ab werkrevisor 0.4.0 kann die Konfiguration stattdessen in der Maschinen-Konfiguration stehen; sie hat dann Vorrang vor der Datei im Image:
```yaml
buildCommand: python -s -m werkrevisor
werkdock:
enabled: true
rootfs: /home/storage/mih09/users/werkator/werkrevisor-rootfs-0.4.0.tar.zst
env:
PATH: /app/.venv/bin:/usr/local/bin:/usr/bin:/bin
PYTHONPATH: /werkrevisor:/app
PYTHONNOUSERSITE: "1"
WERKREVISOR_CONFIG_TOML: |
# vollständiger Inhalt von config/werkprobe.toml, angepasst
```
Modell und Reasoning-Stufe wechselt man dort über `id`, die beiden Preise und `reasoning_effort`; der nächste Review nutzt sie ohne neues Archiv.
Immer die ganze Konfiguration einfügen: Fehlende Abschnitte bekommen Standardwerte, z. B. ohne riskante Pfade.
werkdock bindet auf mih09 das gemeinsame Toolchain-Home des Repositories als `/root`; normale PR-Builds können es beschreiben.
Deshalb startet werkrevisor ab 0.4.0 nur mit `python -s` und `PYTHONNOUSERSITE=1`, liest nichts aus dem Home-Verzeichnis und bricht sonst mit Exit 30 ab.
Ab werkrevisor 0.5.0 wählt `[engine] mode` den Review:
`llm` ist der bisherige LLM-Review und der Standard, `classifier` bewertet nur die PR-Dokumente mit Jev, `combined` beides.
Für `classifier` und `combined` braucht `werkdock.env` zusätzlich `TYPESAFE_API_KEY`;
`config/werkprobe.toml` enthält dafür schon den Abschnitt `[classifier]` mit Fragen und Schwellwerten.
Die Werkator-Build-Definition steht in der Maschinen-Konfiguration auf mih09:
`~/werkprobe/.git/werkator/.werkator.yml` (Rechte `600`), Build `ai-review`.
Ein Branch kann diese Definition weder ändern noch abschalten.
## Secrets und Rechte
| Secret | Fundort | Rechte |
| -------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `GITEA_BOT_TOKEN` | mih09: `werkdock.env` in `~/werkprobe/.git/werkator/.werkator.yml` | Token `pr-agent-bot` von `ai-reviewer`: repository, issue (Lesen und Schreiben), user (Lesen) |
| `OPENROUTER_API_KEY` | ebenda | OpenRouter-Key `review-agents`, Limit 5 USD, monatlich zurückgesetzt |
| `TYPESAFE_API_KEY` | noch nicht eingerichtet; gehört neben `OPENROUTER_API_KEY` | TypeSafe-Key für Jev, nur für `[engine] mode` `classifier` oder `combined` |
| Werkator-Token | mih09: `~/.werkator.yml`, `defaults.git.token` | Token von `mi`; meldet die Werkator-Status |
`ai-reviewer` ist Mitarbeiter mit Schreibrecht nur in `mi/werkprobe`; ohne Schreibrecht zählt sein Approval nicht als offiziell.
Das Konto darf keine Repositories oder Organisationen anlegen.
Eine lokale Kopie der Secrets für Tests liegt auf dem Arbeitsrechner in `~/.config/pr-agent-test/secrets.env` (Rechte `600`).
### OpenRouter-Key austauschen
1. Auf https://openrouter.ai/settings/keys einen neuen Key mit Limit anlegen.
2. Auf mih09 in `~/werkprobe/.git/werkator/.werkator.yml` den Wert von `OPENROUTER_API_KEY` ersetzen.
Werkator liest die Datei beim nächsten Poll, ein Neustart ist nicht nötig.
3. Den alten Key auf OpenRouter löschen.
## Branch Protection von `main` in `mi/werkprobe`
| Feld | Wert | Zweck |
| ------------------------------------ | ---------------------------- | -------------------------------------------------------- |
| `enable_status_check` | `true` | |
| `status_check_contexts` | `werkator`, `ai-review/gate` | CI und KI-Review sind Pflicht |
| `required_approvals` | `1` | das Approval ist die Sperre für YELLOW |
| `enable_approvals_whitelist` | `true` | |
| `approvals_whitelist_username` | `ai-reviewer`, `mi` | GREEN-Bot-Approval oder menschliches Approval |
| `block_on_rejected_reviews` | `true` | RED sperrt |
| `block_on_official_review_requests` | `true` | die YELLOW-Anfrage an `mi` sperrt |
| `dismiss_stale_approvals` | `true` | neue Commits entwerten alte Approvals |
| `block_on_outdated_branch` | `true` | eine bewegte Basis braucht ein Update und damit einen neuen Review |
Die bisherige Regel ist gesichert in `~/.config/pr-agent-test/werkprobe-branch-protections.backup-2026-10-04.json`.
Sie verlangte nur den Status `werkator` und kein Approval.
## Abnahme
| Fall | PR | Ergebnis |
| ------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------ |
| 1. harmlose Änderung | [#8](https://git.javagil.de/mi/werkprobe/pulls/8) | GREEN, Bot-Approval, gemergt ohne menschliches Approval |
| 2. riskanter Bereich | [#9](https://git.javagil.de/mi/werkprobe/pulls/9) | YELLOW, Merge abgelehnt („Does not have enough approvals“), nach Approval von `mi` gemergt |
| 3. eingebauter Fehler | [#10](https://git.javagil.de/mi/werkprobe/pulls/10) | RED mit 2 zutreffenden Befunden, Merge abgelehnt |
| 4. neuer Head, bewegte Basis | #8 | Merge mit alter Basis abgelehnt; nach dem Update gesperrt bis zum neuen GREEN |
| 5. ungültiger Key, Timeout, Budget, abgeschnittene Antwort | lokal mit `tools/dry-run` | jeweils ERROR, nie GREEN |
| 6. wiederholter Lauf | #10, Neustart in Werkator | Urteil wiederverwendet, kein Modellaufruf, kein zweiter Kommentar |
Modellqualität und Gate-Mechanik sind getrennt zu bewerten:
- `gemini-3.8-flash` hat den Fehler in #10 übersehen, Sonnet 5.5 hat ihn gefunden.
- Einen Fehler, der eine Randbedingung außerhalb des Diffs verletzt ([#11](https://git.javagil.de/mi/werkprobe/pulls/11)), fanden weder Sonnet 5.5 noch DeepSeek V4 Pro noch GPT-6 Astra „high“.
Den Merge hat dort die feste Regel verhindert (Kategorie `mixed`).
## Kosten
Gemessen mit den von OpenRouter gemeldeten Kosten:
| Lauf | Tokens (Input / Output) | Kosten |
| ----------------------------- | ----------------------- | ---------- |
| #8, Doku-Änderung, GREEN | 2.936 / 94 | 0,0068 USD |
| #9, CI-Konfiguration, YELLOW | 3.030 / 315 | 0,0092 USD |
| #10, Fehler, RED | 3.497 / 590 | 0,0129 USD |
Der ganze Versuch mit allen lokalen Vergleichsläufen kostete 0,142 USD.
Jeder Kommentar nennt die Kosten seines Laufs; Werkator archiviert `build/werkrevisor/usage.jsonl` als Artefakt.
Fehlende Verbrauchsdaten stehen dort als `unknown`, geschätzte Kosten als `estimated`.
## Bekannte Grenzen
- Das Modell sieht den Diff und die vollständigen geänderten Dateien (ab 0.3.0, `full_files = true`), aber keine anderen Dateien.
Randbedingungen, die nur in nicht geänderten Dateien stehen, erkennt es nicht.
Mit Diff allein hat kein getestetes Modell den Fehler in #11 gefunden; mit den vollständigen Dateien fand Sonnet 5.5 ihn.
- Ein menschliches Approval startet keinen neuen Review; `ai-review/assessment` zeigt deshalb weiter den Stand des letzten Reviews.
Für den Merge ist nur `ai-review/gate` verpflichtend.
- Wenn nur die Basis sich bewegt, startet kein neuer Review; `block_on_outdated_branch` erzwingt dann ein Update.
- Review-Builds teilen sich das Limit `maxConcurrentPerRepository: 1` mit der CI und warten auf sie.
- Bei Modellen mit wechselnden Anbietern (z. B. DeepSeek) kann der tatsächliche Preis über dem eingetragenen liegen.
- `block_admin_merge_override` ist `false`: Ein Gitea-Administrator kann die Sperre beim Merge übergehen.
## Stoppen, neu starten, zurückbauen
**Reviews anhalten:** In `~/werkprobe/.git/werkator/.werkator.yml` den Block `builds.ai-review` auskommentieren.
Solange `ai-review/gate` Pflicht ist, sind dann alle PRs gesperrt; deshalb gleichzeitig die Branch Protection zurücksetzen (siehe unten) oder nur `ai-review/gate` aus `status_check_contexts` nehmen.
**Neu starten:** Den Block wieder aktivieren.
Einen einzelnen Review wiederholt die Werkator-Oberfläche („Restart“) am Build `<branch>@ai-review`.
**Neue werkrevisor-Version:** Mit `tools/build-rootfs` ein Archiv bauen, nach `/home/storage/mih09/users/werkator/` kopieren und in der Maschinen-Konfiguration den Pfad `werkdock.rootfs` auf das neue Archiv setzen.
Beim Wechsel auf 0.4.0 zusätzlich `buildCommand: python -s -m werkrevisor` und `PYTHONNOUSERSITE: "1"` in `werkdock.env` setzen.
Jede Version braucht einen eigenen Dateinamen.
**Vollständiger Rückbau:**
1. Branch Protection wiederherstellen, mit einem Admin-Token von `mi`:
```bash
curl -X PATCH -H "Authorization: token $GITEA_SETUP_TOKEN" -H 'Content-Type: application/json' \
https://git.javagil.de/api/v1/repos/mi/werkprobe/branch_protections/main \
-d '{"status_check_contexts":["werkator"],"required_approvals":0,"enable_approvals_whitelist":false,"approvals_whitelist_username":[],"block_on_rejected_reviews":false,"block_on_official_review_requests":false,"dismiss_stale_approvals":false,"block_on_outdated_branch":false}'
```
2. Auf mih09 die Maschinen-Konfiguration aus `~/werkprobe/.git/werkator/.werkator.yml.bak-2026-10-05-before-ai-review` zurückkopieren.
3. Die Archive `werkrevisor-rootfs-*.tar.zst` in `/home/storage/mih09/users/werkator/` löschen; Werkator entfernt das zugehörige Werkdock-Image selbst.
4. In Gitea `ai-reviewer` und `werkprobe-dev` aus den Mitarbeitern von `mi/werkprobe` entfernen, ihre Tokens löschen und die Konten deaktivieren.
5. Den OpenRouter-Key `review-agents` löschen, sofern ihn nichts anderes mehr nutzt.
6. Den Einrichtungs-Token `pr-agent-setup` von `mi` löschen.