Files
werkrevisor/docs/betrieb-git.javagil.de.md

254 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 oder ORANGE" --> 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` |
| ORANGE | Kommentar mit den Befunden, offizielle Review-Anfrage an `mi`, kein Bot-Review | success | gesperrt bis zu einem Approval von `mi` nach Prüfung der Befunde |
| RED | Kommentar, Review `REQUEST_CHANGES` mit höchstens 3 verletzten Regeln | failure | gesperrt bis zu einem neuen Commit, der die Regel erfüllt |
| 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.
Ab werkrevisor 0.6.0 gibt es vier Farben.
RED (hart) kommt nur noch aus festen Regeln, z. B. aus offenen Fragen im PR-Dokument; kein Approval hebt es auf.
Befunde des Modells und des Classifiers Jev ergeben höchstens ORANGE (weich), weil beide irren können.
ORANGE setzt `ai-review/assessment` auf `warning` und wartet auf das Approval eines Entwicklers, der die Befunde geprüft hat.
Bis 0.5.0 ergaben Befunde des Modells RED.
Ab werkrevisor 0.7.0 gibt es zwei getrennte Größengrenzen:
- `[size] max_changed_lines` und `max_files` zählen nur Dateien außerhalb der Doku.
Ein größerer PR wird ORANGE, weil ein Mensch ihn bewusst freigeben muss; das Modell prüft ihn trotzdem.
- Die Eingabegrenze des Modells ist die kleinere aus `[model] max_context_tokens` und der Grenze, die `[budget] max_usd_per_review` bezahlt.
Ein PR darüber bekommt keinen KI-Review und wird YELLOW.
Jeder Grund aus einer Grenze nennt den Schlüssel und den Wert der Konfiguration, z. B. `[size] max_changed_lines = 800`.
Ab werkrevisor 0.8.0 kann ein Repository eine eigene `.werkrevisor.toml` haben.
werkrevisor liest sie aus dem Basis-Commit und legt sie über die Host-Konfiguration; Modell, Budget und Gate bleiben beim Host.
Für `mi/werkrevisor` enthält `config/werkrevisor.toml` nur noch den Host-Teil, den Rest `.werkrevisor.toml`.
Eine neue Version deshalb erst nach dem Merge dieser Datei installieren.
Ab werkrevisor 0.9.0 prüft der Abschnitt `[writing]` die zählbaren Schreibregeln geänderter Doku; ein Verstoß ergibt ORANGE.
Ab werkrevisor 0.10.0 sind Hauptcode mit nur hinzugefügten Tests freigebbar und DB-Schema-Pfade immer YELLOW.
Ab werkrevisor 0.11.0 zählt werkrevisor den Prompt vor dem Modellaufruf: `o200k_base` × `[model] token_count_factor` (1,15).
Ab werkrevisor 0.12.0 zählt eine Jev-Antwort unter `[classifier] min_confidence` nicht mehr für das Ergebnis.
Ab werkrevisor 0.13.0 braucht die Host-Konfiguration `[mechanical]`; mechanisch geänderte Dateien gehen nicht an das LLM.
Ab werkrevisor 0.13.1 stehen die Gründe im Kommentar nach Schwere sortiert, die schwersten zuerst.
Ab werkrevisor 0.13.2 fehlen im Build-Protokoll die erwarteten 404-Meldungen für neue und gelöschte Dateien.
Ab werkrevisor 0.14.0 hat jeder Befund des Modells eine Schwere;
`[review] orange_min_medium` ersetzt `red_min_findings`, der alte Schlüssel ist ein Konfigurationsfehler.
Ab werkrevisor 0.15.0 braucht die Konfiguration `[hard_orange]`, auch leer; eine Änderung auf diesen Pfaden ergibt ORANGE.
## 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,
ab 0.10.0 auch Hauptcode mit nur hinzugefügten Tests;
- immer mindestens YELLOW: Pfade zu Auth, Rechten, Migrationen, Secrets, CI und Deployment (`.werkator*`, `.gitea/**`, `Dockerfile*`, Build-Dateien);
Dateien der Kategorie `docs` zählen ab 0.6.0 nie dazu, auch wenn ihr Name z. B. `rbac` enthält;
- Secret-Scan der hinzugefügten Zeilen: Ein Treffer führt zu YELLOW, ohne Modellaufruf;
unter `src/test/**` zählen ab 0.6.0 nur echte Schlüsselformate, weil Testdaten erfundene Passwörter enthalten;
- offene Fragen in einem geänderten PR-Dokument (`[pr_doc]`, ab 0.6.0): RED 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- oder ORANGE-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; ab 0.6.0 wäre das ORANGE |
| 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`.
Ab 0.7.0 steht ein Lauf ohne Modellaufruf als `none` mit 0 USD; der Kommentar sagt dann „no model call, cost 0 USD“.
## 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.