213 lines
15 KiB
Markdown
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.
|